I searched every Codex session I could find under my ~/work directory. There were 1,063 indexed threads spread across side projects and consulting work. Twenty-two project trees had a .beads directory in them.

Then I searched for a sentence I knew I had typed too many times:

close the ticket with reason

Eighty-three times. That is after removing exact duplicates.

The earlier sessions looked different. In March and April I kept asking things like:

what bd tickets are currently opened?

Or:

there's a bd ticket about PostHog right?

By July, a normal prompt looked like this:

let's plan bd ngr-dy4.5

That is a ridiculous prompt if the ticket is bad. There is no feature description, no acceptance criteria, and no explanation of what ngr-dy4.5 means.

It worked because I had already done the longer writing somewhere else.

I wrote recently about how the process has to survive the session. Going through these sessions showed me that one part of that process had taken on a much bigger job than I realized. The issue tracker was no longer where I kept a list of work.

It was how I handed the work to the next agent.

The ticket slowly became the brief

I started using Beads in late March. It is a command-line issue tracker that lives with the repository, so an agent can read and update it without leaving the project.

At first, I used it like any other backlog. List the open issues. Find the one about PostHog. Create a ticket for an idea I did not want to work on yet.

This is from an April session on WhatIsThatMovie:

create a bd ticket for that i'll come to it later

That part alone helped. I run enough side projects that "I'll remember this later" has stopped being a believable sentence.

The tickets became much more detailed over time. A WhatIsThatBook ticket about web-grounded retrieval started as an evaluation of Exa. After testing, it carried the decision to use DataForSEO instead, production numbers, three real queries the normal model had missed, the allowlist of sites, the expected cost, the fallback conditions, and the exact parts of the site to update when it shipped.

When I came back to it, I did not have to remember why we had rejected Exa or which Reddit communities were useful. The ticket had the argument, not only the conclusion.

That changed how I used planning agents too. I could give an architect the ticket ID and the repository documentation, then ask for a plan. The agent did not need me to reconstruct three previous sessions before it could begin. The prompt got shorter because the ticket got better.

The graph is more useful than the list

The part of Beads that became interesting once I had several agents working was not the issue text. It was the dependency graph.

bd ready is supposed to return work that is open and has no active blockers. In a well-maintained project, that gives an agent a reasonable answer to "what can I work on now?" It also lets me ask which ticket I can take in parallel without colliding with another session.

I asked versions of that question over and over:

which other ticket can i be doing in parallel?
check epic, what should we work on next?

On NextGoodRole, one agent mapped an epic with 36 issues: five closed, one in progress, and thirty open. Then it found a problem. Every one of those thirty open issues appeared ready, even though the roadmap clearly required some of them to happen before others.

The agent put it plainly: the issue graph had no real cross-task dependencies, so bd ready could recommend downstream UI before the data it needed existed.

A later session found 24 ready tickets and zero blocked tickets. That was obviously not true in any useful sense. Beads was answering the graph I had written, not the project plan I had in my head.

That distinction matters more with agents than it did when the backlog was only for me. I can look at two tickets and remember that one depends on the other. An agent starting cold cannot. If the relationship is missing, both tasks look safe.

Once the dependencies were in the tracker, "what should I do next?" stopped being a planning meeting. The agent could claim one of the genuinely ready issues, and another session could choose a different branch of the graph.

The backlog told us what existed. The graph told us what was possible now.

Done needed more than a green label

The 83 variations of "close the ticket with reason" were the clearest habit in the sessions.

I do not want an agent to close a ticket because the code looks finished. I usually ask it to run the tests, inspect the result in a browser when there is a UI, or check production evidence when the ticket is about a live failure. Then it closes the ticket with the reason it believes the work is done.

The reason can say that the implementation shipped and name the verification that passed. It can also say that we closed the issue without changing code because production data showed the bug no longer existed. Both are useful answers, but they tell the next session very different things.

This turned into a small routine across NextGoodRole, WhatIsThatBook, WhatIsThatMovie, Tethon, and Orathor:

implement
verify
close with reason
back up the beads database
commit the code and tracking state

The Git commit tells me what changed. The closure reason tells me why we considered that enough.

I did not decide this upfront. I kept running into sessions where an issue was marked closed but the useful part of the story was still trapped in an old chat. The reason is a cheap way to stop doing that.

Beads also made a mess

This would be a nicer story if Beads had quietly worked in the background the whole time. It did not.

The version I adopted used Dolt. Across several projects I hit local port conflicts, stale locks, schema mismatches, and a circuit breaker that would keep refusing commands after the original problem had gone away. One command failed because the database did not have the started_at column the CLI expected. Another warning wanted the .beads directory permissions changed from 0750 to 0700.

Then there were the files. I had sessions that were basically me asking what .beads/interactions.jsonl was, whether .beads-backup/*.darc belonged in Git, and how I was supposed to restore the database on another machine. A monitor PID lock even wandered into a diff once.

The storage was durable in theory. I did not yet have a recovery process I trusted.

I kept fixing it instead of removing Beads, which is probably the fairest review I can give the tool. The continuity was worth the annoyance.

Eventually I moved the rules into a shared Beads workflow and backup runbook. It says when to take a backup, what kind of backup is recoverable, how to restore it on a new machine, and what not to do when a schema migration gets stuck. Projects point to the shared process instead of each carrying a slightly different copy.

The runbook exists because the failure happened enough times that improvising had become silly.

The tracker does not remember by itself

Beads did not become useful just because it lived in the repository. A stale ticket is stale memory. A missing dependency gives a confident wrong answer. A closed issue without a reason preserves almost nothing.

The work is in maintaining the handoff while the context is still available. Put the decision in the ticket when it changes. Add the dependency when you discover the order. Close the issue after verification, and write down what made you believe it was done.

And the agents are not the only ones who need it. An August session on Orathor started with this:

I don't remember exactly ... check the bd ticket or check the commit history to see if you can find the context

That sounds like ordinary issue tracking. Maybe it is. What changed for me is who reads it next, and how often that reader is me with no idea what I was doing three weeks ago.

I used to write tickets so future me could remember what I meant. Now the next reader is often an agent with the repository open and none of the conversation that produced the task. It needs a bounded place to start, enough context to plan, and an honest record of what the previous session finished.

That is why this works:

let's plan bd ngr-dy4.5

I am not asking the agent to guess. I am pointing it to the longer conversation we already saved.

The ticket is the handoff.