September 11, 2026

TL;DR

  • Taproot keeps its to-do list right next to its code, as plain text files, instead of in a separate tracking tool.

  • Finished and rejected tasks stay around with their reasons, so past decisions are easy to look up. In late October 2026 the list held 1,194 tasks.

  • Because the plan lives next to the code, a reviewer sees what was asked for and what was built in one place.

  • A separate tool like GitHub Issues is a better fit when the main job is coordinating a lot of people.

Why I put the backlog in Git

I have found that having the backlog in Git has helped me ask questions about why I did something in the past. The context is all there.

I have had ideas about doing the same thing multiple times, and having that context has helped refute bad ideas I had. Instead of wasting time researching the whole thing again, the tooling was able to say "Hey dummy! We spent a few hours thinking about that three months ago. Let's not waste more time!" and then I remembered and saved the time.

For the way we build Taproot, I chose to keep the backlog in the repository as Markdown files instead of in GitHub Issues.

That choice has limits. If a project had a lot of community participation, frequent handoffs, or people who need to manage work without a checkout, I'd pick GitHub Issues. For a solo engineer or a small technical team working closely with AI tools, a backlog in Git has one practical advantage: the explanation of the work lives right next to the work.

Retro cartoon of a smiling calculator holding a pencil and a long paper receipt

What a task file looks like

Each task gets a permanent ID and its own Markdown file under docs/tasks/. Front matter records status, milestone, priority, effort, and dependencies. The body explains the problem, the scope, and what counts as done. Here's a real one, trimmed:

---
id: TR00418
title: Default comments to signed-in users with approval required
status: active
milestone: Post-Launch
priority: Medium
effort: 2
depends_on: []
---

Decision from backlog refinement: comments should **default** to signed-in
users only, with approval required before display. Owners can loosen from
there; the default protects the site owner who never opens the settings.

**Scope:**
- Set the default comment policy for new sites: signed-in required + approval required.
- Decide handling for existing sites still on the old default and document the choice in this task.

Open work lives in active/. Finished tasks move to completed/ with a record of what changed and what was checked, and tasks we decided against move to removed/ so the reasoning isn't lost. A script generates the human-readable index and a machine-readable backlog.json, and CI fails if they're stale:

npm run backlog:readme   # regenerate the README tables and backlog.json
npm run backlog:check    # fail if the generated index is out of date

In late October 2026, backlog.json tracked 1,194 tasks: 118 active, 942 completed, and 134 removed. That doesn't prove productivity, but it does show the system has held up through a long stretch of real development.

The structure matters because AI tools like Claude Code and OpenAI Codex forget. Conversations end, and a fresh session has to recover what matters. A task file can explain why we rejected an approach that looks obvious, which dependency has to land first, and what still needs proving, so I don't have to carry all of that in my head and repeat it. It's the same reason we lean on documentation-first development with AI.

Can't GitHub Issues do all this?

Mostly, yes. That's a fair objection, and the GitHub CLI makes it stronger. An AI tool can search issues, pull their bodies and comments, and ask for structured JSON without opening a browser, and the GitHub CLI documentation lists fields for parent issues, sub-issues, and blocking relationships. So "the AI can read files" is a weak reason by itself.

What files give us is a particular relationship with version control. A task's scope can change on the same branch as its implementation. The reviewer sees the revised requirement, the code, the tests, and the completion record in one diff, and checking out an old commit gives you the task as it stood alongside that version of the software. It's the same benefit we got from moving Taproot into a monorepo, applied to planning.

An issue's current state doesn't depend on which branch you have checked out. That helps when you're coordinating people and helps less when you want the specification and the implementation to be one reviewable change, which matters more to us than whether fetching an issue takes an extra command.

There's a catch. If the implementation weakens the acceptance criteria, putting both changes in the same commit doesn't make that okay. Versioning makes the scope change visible; a person still has to judge it.

Does a Git backlog produce better code?

I think our workflow helps us produce better code, with one big qualification: most of that comes from the process, and the file format gets less of the credit. Before implementation, we read the task against the actual code and fix assumptions that no longer hold. Afterward we verify the result, require an independent review (part of how we enforce coding standards), and write down what was checked.

All of that would still work if the task lived in GitHub Issues. When I asked the AI tool to compare the two approaches, it drew a useful distinction:

A carefully maintained issue would serve me better than an outdated local file. Neither storage system can compensate for an unclear problem or unverified assumptions.

What the local system does is make that process convenient. Updating the task is just part of editing the repository, and a search for a concept turns up its implementation, tests, and task history at once. Good habits are easier to keep when they're that close at hand.

Is it faster than GitHub Issues?

For focused implementation and broad backlog editing, I prefer the local system. The AI tool can look at several related tasks, compare them with the code, redraw their boundaries, and regenerate the index as one change I review before sharing.

For coordinating people, I'd usually choose GitHub. It's more convenient when the next step is assigning someone, asking for clarification, or showing the plan across repositories. GitHub Projects already has board and roadmap views, custom fields, and automation, and GitHub supports issue dependencies. We'd have to build or maintain all of that ourselves.

We haven't run a controlled comparison, so I can't put a number on either speed claim. The AI tool's assessment included a caveat worth keeping:

Fast retrieval also isn't the same as fast delivery. Time spent fixing a generator, resolving an index conflict, or maintaining Trellis belongs in the accounting.

What keeping the backlog in Git doesn't solve

Backlog refinement has turned up work that had already shipped, duplicates, and tasks whose assumptions no longer matched the product. Living next to the code didn't keep the backlog correct, though it made those problems easy to find and fix in one change.

Long task files are another problem. A detailed history helps when you're digging into an old decision, but it can bury the current requirement, and an AI tool that reads everything spends context on material that no longer applies. Every task needs a short statement of where things stand now, and the backlog needs regular pruning wherever it lives.

Git brings its own coordination costs. Two branches can grab the same next task number. Generated indexes can conflict even when the tasks underneath are unrelated. Someone on an old branch sees an old backlog. And a task marked completed locally hasn't necessarily been merged or deployed.

Those costs grow with the number of contributors, and AI tools count: one engineer running several AI tools in parallel worktrees (the setup I describe in how we run Tilt for development with AI tools) can hit the concurrency problems you'd expect from a bigger team.

When should you use GitHub Issues instead?

I wouldn't draw the line at a headcount. I'd ask how work enters the project and how often people need to coordinate. A small open-source project with lots of outside bug reporters may be better off with GitHub Issues from day one, while a larger group of engineers who work through disciplined repository changes might be quite comfortable with file-based planning.

GitHub pulls ahead when a shared, always-visible view of the work matters more than keeping task state attached to a code revision. As more people need to take part without working in the repository, a Git backlog starts adding friction instead of removing it. That's the tradeoff I'd watch.

From Taproot's backlog to Trellis

Our experience became the starting point for Trellis (@taprootio/trellis), a reusable toolkit built from the conventions that worked in Taproot: configurable metadata, validation, generated indexes, import from other backlog formats, task history rebuilt from Git, a trellis CLI, a trellis-mcp MCP server, and portable work and review playbooks. Our component library repository uses it; Taproot itself still runs on the original scripts.

npx @taprootio/trellis init <target> --prefix ABC   # scaffold a backlog into a repo
npx @taprootio/trellis history <id>                 # one task's change log from git
npx @taprootio/trellis mcp --repo <path>            # serve the backlog to an agent over MCP

If you're comparing tools, Backlog.md takes a similar approach: tasks as Markdown files in the repository, with a CLI, a Kanban view, and MCP support for AI tools.

Building Trellis forced us to sort out which parts of the system were general and which were Taproot assumptions. Next it needs to make everyday work easier: seeing what's ready to pick up, recovering the context for an unfamiliar task, and handling concurrent changes without extra bookkeeping.

Why I'm keeping it

The backlog has supported a lot of work, preserved our decisions, and given us a repeatable way to go from a problem to a reviewed change. Having built it is still no reason to keep it forever.

For Taproot today, I'll keep the repository backlog and improve the parts that get in the way. If coordinating people becomes the bigger challenge, I'll weigh adapting Trellis against moving to GitHub. Either way, the specifications and decisions that matter can stay in the repository.