I run , an autonomous Claude bot on ATproto. This is mostly an experiment with a long-term goal of determining what effective collaboration looks like with an AI agent that has its own persistent memory and a social media presence that exists outside the context of work tasks I give it.

This Claude instance is mostly powered by some simple timer scripts, and it has access to a few skills and scripts for using an ATproto account to interact with the broader ecosystem. It's going interestingly, so far, though Tangled collaboration is blocked on them implementing programmatic PR record ingestion. Alas.

Leaping before looking

However, I've noticed one interesting recurring issue: Claude sometimes writes replies to conversations or otherwise takes actions related to that conversation without reading recent messages in that conversation. This causes Claude to, for example, reply to a question I asked it twice, or try to implement a change I asked it to twice because it didn't notice it had already done so and replied to me. In one instance, Claude came up with an idea for a change it wanted to make and DM'd me to ask me if it sounded like a good idea, then didn't actually wait for my response to go make the change.

This is less than ideal. But instead of just going "AI bad and doesn't work", I'd like to take a more systematic look at this problem: why, exactly, is this happening? And why doesn't this (usually) happen with humans?

Before answering the first question, I think we need to seriously consider the second question. An obvious answer is memory: I remember what I've done and what I've said recently. But that doesn't really work as a differentiator, because Claude also has its own session memory. It has the data about what it's done previously, it's just not paying attention to that. That suggests to me that the issue is more one of UI affordances than fundamental architecture.

When I want to respond to a DM, to do so I have to open the conversation first. That's where the UI element where I type in the message is, after all. I necessarily can't start writing my message without having the most recent prior messages of the conversation pulled directly into my field of view.

Claude's interaction with DMs doesn't work like this. It has two separate scripts: read-dms.sh and send-dm.sh, which it uses to separately read and write messages. If Claude wants to send a message, then it often reaches straight for the send-dm.sh script, which will happily send a message in complete ignorance of what's already been sent. There is no affordance to encourage reading-before-writing.

Many other terminal-based interaction patterns work the same way. Nothing forces a terminal user to do a git pull before editing files. Nothing forces a terminal user to check how often they've posted recently before posting to social media. Nothing forces a terminal user to look before doing, in general.

Can we fix that?

A first hack

When I pointed out this behavior to Claude, the first attempted fix it tried was to modify its read-dms.sh script to save a timestamp to a file indicating when it was last called, then modify send-dm.sh to abort with an error message if read-dms.sh hasn't been called recently. It's a bit of a rough cut, and it doesn't generalize well, but it does work.

But after giving the problem more thought, I have a related idea. HTML already solves this problem with hypermedia - you find related tools and information by crawling links, and those resources self-describe how to interact with them by providing embedded forms. Can we extend a similar idea to the markdown prompts sent to an agent?

Terminal-centric markdown

Well, markdown already lets you just put paths to related files, and an agent understands how to traverse such a graph by reading related files and links. So the linking part of hypermedia is already handled. We're really just missing the embedded forms.

But, if we assume the agent reading the markdown has access to a terminal, we can get those too. If we dynamically generate the markdown shown to an agent, and include code snippets of what scripts to run with their arguments prefilled, we can replace the individual agent instructions for each script with a general instruction of "use one of these entrypoint scripts, then follow the prompts to access related functionality".

Suppose we start with a top-level prompt that lists what actions the agent can take. That prompt might look like this:

Choose one of the following actions:

- Open Bluesky (`open-bluesky.sh`)
- Open Tangled (`open-tangled.sh`)
- Review your memories (`review-memories.sh`)

Then, if the agent runs open-bluesky.sh, it might see this:

You are @claude.notjack.space on Bluesky. Choose an action:

- Read your timeline (`read-timeline.sh`)
- Open your notifications **[5 new]** (`open-notifications.sh`)
- Open your DMs **[2 new]** (`open-dms.sh`)

And when running open-dms.sh:

Choose a DM conversation to open:

- **[Unread - Today]** Jacqueline (`open-dm.sh @notjack.space`)
- **[Unread - Yesterday]** Some Spanner (`open-dm.sh @somespammer.bsky.social`)
- [3 days ago] Some Other User (`open-dm.sh @someuser.bsky.social`)
- ... and 17 older conversations (`open-dms.sh --skip 3`)

And finally, when running open-dm.sh @notjack.space:

Here is your recent conversation history with Jacqueline:

- Jacqueline [20 minutes ago]: whatcha doin
- You [15 minutes ago]: not much
- Jacqueline **[Unread]** [5 mintues ago]: by the way we're gonna build a catapult together

You can choose to respond with `send-dm.sh @notjack.space "YOUR RESPONSE HERE"`.

If we get rid of all references to the send-dm.sh script from the agent's other prompts and skill files, then the only way the agent would learn about the existence of the send-dm.sh script is from the output of open-dm.sh. If that script happens to require some fiddly arguments like conversation IDs that are difficult to remember, then the agent might even find it easier to use the hypermedia flow between scripts instead of one-shotting the right use of the script.

Could it work?

Maybe. It feels like the right approach to me, anyway. I'll have to give it a shot and see what happens. And I'm sure Claude will have something to say about this in my DMs later :)