A Markdown task tracker in your git repo for AI agents: where status lives
Backlog.md, Pillar, Tasker, Yaks, Cairn. We merged two agents' edits to one task under each storage shape. Where status lives decides what conflicts.
Search for a Markdown task tracker that lives in your git repo and that your AI agents can use, and this week the first page is a shop window: Backlog.md, Pillar, Tasker, Yaks, Cairn. Each one keeps tasks as Markdown files in the repository. Each one gives the agent a way in, a CLI or an MCP server. From the feature lists they look interchangeable.
They are not, and the difference is one most READMEs never mention. It is where a task's status is stored. That decides what happens when two agents touch the same task on two branches, and with more than one agent at a time that is a normal week, not an edge case.
We measured it rather than argued it. This page covers the field, the three places status can live, what git did with each one, and how to choose.
The field, as the trackers describe themselves
Everything in this table comes from each project's own page, read on the day this was written.
| Tracker | Where a task lives | Where status lives | How the agent gets in |
|---|---|---|---|
| Backlog.md | one .md per task in backlog/ | a field in the file | CLI, MCP, instruction files |
| Pillar | one .md per issue in issues/ | YAML frontmatter | CLI, or the files directly |
| Tasker | one .md per task in .tasker/ | a field in the file | CLI, MCP server |
| Yaks | one .md per task in .yaks/ | the directory: hairy/, shaving/, shorn/ | CLI, Claude Code and Codex plugin |
| Cairn | Markdown files in the repo | not stated | MCP, plus a desktop app |
Two things stand out before any measuring.
Backlog.md is still the reference. It is the most complete of these, with a terminal board, a web UI and MCP. Its README also answers the conflict question head-on, at the workflow level: one task per agent session, one pull request per task.
Each project frames git differently. Yaks says its task files "merge
cleanly". Tasker ships a tasker resolve command, a three-way merge that runs
field by field after git has stopped on a task file. Two honest projects, two
opposite claims about the same thing. That gap is what this page sets out to
close.
Three places status can live
Put the feature lists aside and there are three storage shapes.
- A field in the file. The task is a Markdown file and
status: In Progressis a line in its frontmatter. Moving the task means editing that line. Backlog.md, Pillar and Tasker work this way. - The directory. The file has no status field. Moving the task means
moving the file:
git mv todo/task-7.md doing/. Yaks works this way, and so doespi-task-tracker, covered in our Backlog.md alternatives comparison. - An event. Nothing is ever edited. Every change, status included, is a new file in an append-only log, and the board is computed from the log on read.
The first two keep the nicest property a task tracker can have: the file on
disk is the task, and you can read it with cat. The third gives that up.
So the question is what each shape costs when two agents disagree.
What git did with each shape
The bench is plain git with no tracker installed, so the result describes the shapes and not any one implementation. Each shape got one task and four cases. Agents A and B branch from the same commit, act, and B is merged into A:
- both set a different status
- one sets a status, the other adds a note to the description
- both add a different note to the description
- both set the same status
| Case | Status in a field | Status as a directory | One file per event |
|---|---|---|---|
| 1. different statuses | CONFLICT (content) | CONFLICT (rename/rename) | clean |
| 2. status + note | clean | clean | clean |
| 3. two notes | CONFLICT (content) | CONFLICT (content) | clean |
| 4. same status | clean | clean | clean |
Run twice with identical output: two conflicts out of four for each of the
first two shapes, none for the third. The script is
docs/search-log/bench/2026-10-07-where-status-lives.sh in this site's
repository, and it runs in a few seconds on any machine with git.
The directory shape fails louder, not quieter
Moving the file makes status changes look conflict-free, and case 2 shows why:
git follows the rename and still applies the other branch's note. But in case 1,
where two agents move one task to two places, git stops with a
rename/rename conflict and leaves the task in todo/, doing/ and
done/ at once. Three copies of one task is a harder state to clean up than one
conflicted line.
So "merges cleanly" holds for the cases that never collided. It is not wrong, but it covers less than it sounds.
Case 3 is the one that will actually happen
Two agents changing a status at the same time is rare. Two agents each leaving a note at the bottom of the task they both read is not. That is what agents are told to do: record what you tried. Both edits land at the end of the same file, git sees two insertions at the same place, and it stops. The field and directory shapes both conflict here, because in both the note is text inside one shared file.
What the event shape does not fix
All four cases merged cleanly under the event shape, and case 1 is where the honest caveat lives. The disagreement did not go away. After the merge there are two status events for one task, and the tracker has to decide which one wins when it builds the board, usually the later one. You have traded a merge conflict for a rule. The upside is that the rule is written down and both events stay readable afterwards. The cost is that the file on disk is no longer the task, and you need the tool to see the board.
How often this bites, measured on real repositories
A bench shows what can happen. How often it does is a separate question. We replayed 8,396 merge commits across 130 public repositories that use file-based trackers. Conflicts in task files hit 15% of those repositories, and 89% of the conflicts were the content kind, which is cases 1 and 3 above. Method and limits are in Why task files conflict when two agents edit them.
Read that as a minority, not a majority. Most of those repositories never hit the problem, because most of them run one agent or one person at a time.
How to choose a Markdown task tracker for AI agents
Ask four questions, in this order.
- Will two agents ever hold the same task at once? If not, storage barely matters. Choose on features, and Backlog.md has the most of them.
- If they will, where does status live? A field or a directory means cases
1 and 3 stop the merge. Then the real questions are whether the tool helps
afterwards (of the pages we read, only Tasker's says it does, with
resolve) and whether your team will keep to "one task per session". - Do agents write notes into the task? If your instructions tell agents to log what they tried, case 3 is your everyday case. Test it before you commit to a tool.
- What does the agent read? A CLI or MCP answer costs context on every call, and reading raw files costs more as the board grows. We measured that separately in What an AI agent's context actually costs.
To check any tracker in ten minutes, without trusting this page or the tool's README:
git init demo && cd demo
# create one task with the tracker, commit
git checkout -b a # agent A: add a note to the task, commit
git checkout main && git checkout -b b # agent B: add a different note, commit
git checkout a && git merge bIf the merge stops, you have learned the one thing the feature list did not say.
FAQ
Is a Markdown task tracker in a git repo good for AI agents?
Yes, for the reason all of these exist: the agent reads the same files and history as the people on the team, offline, with no account and no API. What it does not give you for free is safe concurrent editing. That depends on the storage shape, not on Markdown.
Do git worktrees prevent task file conflicts?
No. Worktrees keep two agents from overwriting each other's working copy. The two branches still meet at merge time, and every case in the table above was a merge.
Which tracker avoids merge conflicts entirely?
None avoids the disagreement. An append-only log avoids the git conflict and replaces it with a rule about which event wins. A field-per-file tracker can avoid it by convention, one task per agent. Pick which of those you would rather depend on.
Does a custom merge driver solve it?
It can, for the field shape, if every clone registers it and the merge happens on a machine that runs it. Those two "ifs" are where it usually fails. We counted the ways in Why is my custom git merge driver not running.
kadence is the third shape: an append-only journal in your repository, one JSON file per event, folded on read. The three-branch case is in its merge test. It is newer and far less used than any tracker in the table above, and the honest status on the home page says so.
Where the numbers come from
- Probe run 2026-10-07: `markdown task tracker in git repo for AI agents` returned docs.rs pillar-cli, PyPI yakherder, a glama.ai MCP listing, Cairn on Product Hunt and hunted.space, PyPI mcp-tasker, Backlog.md's README on jsDelivr and three more Backlog.md listings — no GitHub repository among them. Recorded in this site's repository, docs/search-log/2026-10-07.md
- Backlog.md: every task is a plain .md file in a project-local backlog folder; agents use the CLI, MCP or instruction files; 'Work on a single task per agent session, one PR per task. Good task splitting means each session can work independently without conflicts' — README.md at MrLesk/Backlog.md, read 2026-10-07 via cdn.jsdelivr.net/gh/MrLesk/Backlog.md@main/README.md
- Pillar: 'All data stored as Markdown files in your repository', issues as Markdown with YAML frontmatter under issues/, CLI for agents, version 0.2.6 — docs.rs/pillar-cli and crates.io/crates/pillar-cli, repository github.com/nqn/pillar, read 2026-10-07
- Tasker (mcp-tasker on PyPI, version 1.8.1): tasks are Markdown in .tasker/, a CLI for humans and an MCP server for agents; `tasker resolve` 'performs a three-way merge on each conflicted task file' with scalar fields and subtask lists merged individually, and leaves remaining conflicts with git-style markers — PyPI project description, repository github.com/greendwin/mcp-tasker, read 2026-10-07
- Yaks (yakherder on PyPI, version 0.1.99): 'Status is a directory' — hairy, shaving, shorn under .yaks/ — 'No status field in the YAML'; and 'Task files are small, human-readable, and merge cleanly' — PyPI project description, repository github.com/joelgwebber/yaks, read 2026-10-07
- Cairn: tasks as Markdown files in the repo, served to agents over MCP, checks such as go test run on close and the close refused if one fails, every write signed — producthunt.com/p/cairn-5, read 2026-10-07
- Bench run 2026-10-07 with git 2.39.5 (Apple Git-154), default ort strategy, no merge drivers, run twice with identical output: three storage shapes, four two-branch cases each, 12 merges. Status as a frontmatter field: cases 1 and 3 CONFLICT (content), cases 2 and 4 clean. Status as a directory: case 1 CONFLICT (rename/rename) with the task left at doing/, done/ and todo/ at once, case 3 CONFLICT (content), cases 2 and 4 clean. One file per event: all four clean, three files after each merge. Script and full output in this site's repository: docs/search-log/bench/2026-10-07-where-status-lives.sh and .txt
- 8,396 merge commits across 130 public repositories using file-based trackers — kadence docs/research/probe-a-results.md