todox
Sign in

blog · 19 September 2026

Six weeks on our own log

We built a memory server for coding agents and pointed it at ourselves: what the agents wrote, what they never closed, and the feature we were proudest of that nobody called.

measured 1–18 September 2026 on one account · 31 repositories, 2 machines, 4 models

todox is an MCP server. An agent calls get_context at the start of a session and gets a briefing: the standing rules, the open tasks, the decisions behind them, the approaches that failed, and where the last session stopped. While it works it writes entries — decision, dead_end, question, handoff — and before it stops it is supposed to leave the log in a state a stranger can resume from.

“Supposed to” is the part this post is about. We have been the only serious user for six weeks: one account, 31 repositories, a laptop and a desktop, four Claude models. The instructions were four lines in the memory file every agent reads. Here is what the data says they did with them.

330entries in 18 days — about 18 a day
31dead ends, 9% of the log
78 / 29tasks opened / closed
5,430 h“active” time the report summed, in 18 days
0calls to link_files from the agents
1question entry in the month

From activity_report and get_context over the todox MCP, 2026-09-18. Every number below comes from the same place.

FINDING 1Capture works, and dead ends get written

The fear with a curated log — one where the agent decides what is worth keeping, rather than a transcript dump — is that nothing gets kept. It did not happen. Eighteen entries a day across a working month, and 82 of them decisions with the alternative that lost named in the body.

The one we cared about most is the dead_end: the approach that looked right, cost an afternoon and failed for a reason nobody writes down. Thirty-one of those. Some are one line (“Playwright context.route() for blocking images increases proxy bandwidth 3–11×, measured — do not”). They are the entries that stop the next session repeating the afternoon, and agents write them when the kind exists to write them into. A note in a file has no such kind, so the failed approach goes into the same paragraph as everything else, or nowhere.

FINDING 2Closure does not, and the report lied about it

Seventy-eight tasks were opened in the window and twenty-nine were closed. That alone is fine — work is open. What was not fine: tasks had been set to doing by a session that then ended, and stayed there. Sixteen days. Twenty-three. Thirty-one. Every one of those days sat on the activity report as time worked, because the report summed every hour a task spent in doing. One project showed 1,316 hours of work in an 18-day window. The account showed 5,430.

A duration that can only grow is not a measurement. The status column is a claim; the log is the evidence.

The instructions had said, clearly, “before you finish, set every task you touched to its true status.” Every agent read that at the start of every session. The rule was never the problem. The list was: an agent at the end of a long session does not remember which tasks it moved, and a rule cannot tell it. So we did two things.

FINDING 3The feature we were proudest of was never called

todox can link files to a task with their hash. The agent hashes the file (the server has no checkout), and the next briefing says whether a note describes code that has since moved on — “this note may be lying” — or, until somebody has actually looked, “not checked”, rather than claiming to be fresh. We wrote about it on the landing page. It is the thing a note in a file cannot do.

Zero calls. Every task in the month had files: []. The reference ids on the whole instance, smoke tests included, had not reached forty.

Two reasons, one embarrassing. The instructions said the agent could link files; they never said which. Meanwhile every task body pointed at the thing that actually drove the work — a plan file under ~/.claude/plans, a claude.ai artifact — and nothing said that those were exactly what to link. The embarrassing one: a path linked from Windows was stored with backslashes and compared, on lookup, against a path folded to forward slashes. Equality never held. The few links that existed could not be found again, on the machine that made them or any other. The smoke test failed on Windows at precisely that step, and we had only ever run it on Linux.

Now the instruction is concrete — “put the plan a task follows in files, wherever it lives; todox warns when it moves on” — a URL is accepted and kept as written, and paths are folded on the way in.

FINDING 4Connected is not used

This one we had measured before and it is worth repeating, because it applies to every MCP server. An MCP server can send instructions at initialize. Ours did: the whole protocol, when to call what. In a fresh project, with the server connected the entire time, the agent never called it once. The server’s instructions are background reading; a skill or a rule in the agent’s own memory file is an instruction. When they disagree, the server loses.

The fix is four lines in the file the agent actually obeys, and an installer that writes them. This week it is also a Claude Code plugin — the same four lines, installed rather than pasted, with one sentence injected at session start by a hook, which is the one channel a session cannot skim past.

FINDING 5The briefing grows with what nobody closes

The briefing every session opens with is capped in rows and in bytes, and it reports what the caps left out rather than trimming in silence. On the busiest project it left out 48 log bodies and 16 task bodies. Most of the tasks paying for those bodies had not been touched in weeks, so we added a tier: a task idle for fourteen days comes back as a line — title, status, days idle, the last handoff’s first line — outside every budget. On a bench corpus with six idle tasks the briefing went from 37.9 KB to 25.6 KB and the live log arrived whole.

On the busiest project it moved one task. Eighteen of its nineteen open tasks had been touched in the last two weeks, nine of them still doing. Its problem is not an idle tail; it is that live work does not get closed. That is Finding 2 again, and the honest thing to say is that the tier helps projects with a long idle tail and session_status is what helps this one.

FINDING 6Two small ones

The question kind is nearly unused — one entry in the month — and it is not a failure. Questions get asked and answered inside the session; the kind is for the one that has to wait for a human across sessions, and that is rare by nature. We stopped counting it as a metric.

Search is language-locked, and its snippet was bolding “of”. An English question did not find the Turkish decision note that answered it — full text stems, it does not translate, and the tool description now says to ask in the language the log is written in. The snippet was a real bug: the match was made on the stopword-stripped query, but the highlight was made on the raw one with a configuration that has no stopword list, so it bolded every “of” in the document and picked the fragment densest in them. A two-letter query, stripped to nothing, was matching every row containing those letters. Both fixed at the source of the query text.


If you write an MCP server

  1. Your instructions are background reading. Put the rule where the agent obeys — its memory file, a skill, a session hook — and measure whether the tools get called, by method. “Connected” is not a number.
  2. If a status can be set and forgotten, your reports will lie. Count evidence, not claims. A span of “in progress” with nothing else in the log to show anyone was there is not work; say how much you discounted, rather than folding it into the headline.
  3. The list beats the rule. “Write up every task you touched” is a rule the agent cannot follow at the end of a long session. A tool that answers “what do I still owe” is something it can act on. Make it read-only so the client never asks permission at that moment.
  4. Tell the agent what to link, not that it can. A capability with no concrete instruction is a capability with zero calls.
  5. Run the smoke on the platform your users have. Ours failed on Windows at a step we had only ever proven on Linux, and the failing step was the feature we advertised.

What changed this week

FindingChangeMeasured
2Attended time; discounted_ms on the headline, task lines and the report page5,430 h → what the log supports
2session_status, read-only; wrap-up rule begins with itlive, both transports
3Paths folded on link; URLs kept; “link the plan” in the instructionsWindows smoke passes the step
5Idle tier in the briefing (14 days)37.9 → 25.6 KB on the bench
6Snippet on the stripped query; substring arm off under 3 characters“of” → 0 hits
4Claude Code plugin: server + skill + session-start reminder2 commands to install

todox is MIT and runs as one container beside a Postgres: the code, the hosted one. Every figure here is from activity_report and get_context on our own account, and the pull requests behind the changes are #129–#136 in the repository. If your agent already remembers things — Claude Code has written its own notes since February — this is not a replacement for that. It is the log that crosses the lines that memory stops at: two machines, every agent, the people.

decisiondead endquestionhandoff