My coding agents used to read their tasks from a hosted tracker. They never needed one. They needed a folder of markdown files, and I needed a small board to look at them.
This is how I worked that out, and the tool that came from it: board.md, a local board for the markdown task files already in your repo.
Where I started: a hosted tracker, an MCP server, and a limit
I was about to pay for a database when the only reader of the data was an agent that reads text.
I run several projects with coding agents. The tasks lived in Notion, on the free plan, and the agents pulled task details through its MCP server. It worked. But with a few projects I was close to the free plan's limit, and the next step would have cost me about $40 a month. It would have gone the same way with Jira, Monday or ClickUp: the limit and the price differ, the problem doesn't.
Before paying, I looked at what the agents actually did with a task. They read the title, the notes and a few fields. Then they changed a status. That was all.
What an agent needs from a task tracker
An agent needs a file it can read and edit. One markdown file per task, in the repo, with the fields in YAML frontmatter and the notes below:
---
id: DEMO-4
title: "Projects CRUD"
status: todo
phase: P2
module: projects
priority: P0
size: M
branch:
pr:
---
# DEMO-4 Projects CRUD
Soft delete. Names unique per account, ignoring case.
That format beats a hosted tracker for an agent in four ways:
- No API. The task is in the same checkout as the code. There is no token, no network call and no rate limit.
-
It ships with the work. The pull request that builds the task also sets its status, so the board on
mainalways shows what is merged. - It gets reviewed. A changed status is a line in a diff, like everything else.
-
History is free.
git logon the file is the task's history.
One of my projects already worked this way, with 88 task files. The agents were happy. I was the problem.
What I needed: a board
I needed to see 88 files as columns and drag a card from one to the next. Nothing more.
My first plan was something bigger, with a database behind it. I didn't need any of that: the files were already the database. The markdown kanban tools I looked at each wanted their own file layout, and I didn't want to convert files my agents already understood.
So board.md reads the files you have. npx boardmd init looks at them and works out a config: the id format, the statuses, which fields become badges or filters. npx boardmd serve shows the board on localhost.
[image: Demo: a card dragged from Todo to In progress changes one line in its file; boardmd new creates a task and its card appears on the board]
Status you don't have to maintain
"In progress" and "in review" are not written in any file. The board reads them from git each time it loads.
- A local branch named for a task, like
task/demo-4-projects-crud, shows that task as in progress. - An open pull request shows it as in review, labelled draft, approved or changes requested.
- A merged pull request whose file still says
todogets a badge, so you can see the file is behind.
This matters most with agents. My agent creates a branch, does the work and opens a pull request. The card moves across the board by itself, and nobody edits a status until the pull request sets it to done.
The one-line diff
When I drag a card, exactly one line of one file changes:
-status: todo
+status: in-progress
This is the rule the tool is built around. The files belong to the agents and to code review. A board that re-serialises the YAML reorders keys, changes quotes and turns a status change into a noisy diff that conflicts with the next branch.
So a drop does very little, on purpose:
- The page sends the new status with a hash of the file as it last saw it.
- If the file changed on disk since then, nothing is written and the card reloads.
- Only the value on the
status:line is replaced. The key, spacing, quotes, any comment and the line ending stay as they were. - The file is written to a temporary file and renamed over the original.
A file with no status: line is refused, not given one. The board never commits or pushes; a banner lists the files you changed so you can.
Agents are users too
An agent gets the same guarantees as the board, through four commands.
| Command | What it guarantees |
|---|---|
boardmd list --json |
Every open task with its fields, its file and its live state from git. |
boardmd new "<title>" --set phase=P2 |
The next id, the right folder and file name, and frontmatter in the same order as the other files. |
boardmd set DEMO-4 status=done pr=41 |
Only those lines change. It warns if git shows the task in progress or in review. |
boardmd check |
Every file is validated: ids, file names, folders, required fields, allowed values. |
Before these existed, creating a task meant the agent guessed the next id, the folder and which fields to fill. Now a wrong guess gets an answer it can act on:
$ npx boardmd new "Half a task" --set priority=P9
Can't create the task: priority must be one of: P0, P1, P2; set phase (P1, P2),
module, size (S, M, L) with --set <field>=<value>.
An agent also can't use a tool it doesn't know is there. So boardmd init offers to add a short section to CLAUDE.md or AGENTS.md, and a Claude Code skill. Both point at boardmd guide, which prints this repo's own rules from the config: where tasks live, the next id, the allowed values for each field and how branches are named.
For Claude Code there is also a plugin. /plugin marketplace add anojanst/board.md, then /plugin install boardmd@board-md, adds /boardmd:setup to set a repo up and /boardmd:board to open its board.
Try it
Three commands, from the root of a repo that has task files:
npm install --save-dev board.md
npx boardmd init
npx boardmd serve --open
init shows what it found and asks before writing anything. With no task files yet, it offers to create a tasks/ folder with an example. You need Node 20 or later. git and the GitHub CLI are optional: without them the board works, just without branch and pull request state.
It is free and open source (MIT): npm, GitHub.
What it doesn't do
board.md is deliberately small, and these are the edges:
- One person, one machine. It serves on localhost. There are no accounts and no hosting.
- GitHub only for pull requests. That state comes from the GitHub CLI. Branch state works with any git repo.
-
The board edits status only. Other fields change through
boardmd set, or in your editor. - It never runs git for you. No commits, no branches, no pushes.
If a team needs comments, assignments and reports, a hosted tracker earns its price. If your agents already keep tasks in markdown, point board.md at them and tell me what breaks.
Top comments (1)
tr.ee/dev-to
Some comments have been hidden by the post's author - find out more