diarie
A task tracker you cannot be trapped by.
Your backlog is YAML in your repo. The CLI is a reader over files you own. Uninstall it — and your backlog is still there.
npm install --save-dev diarie
no daemon · no database · no git hooks
The record is yours
diarie reads a backlog that already lives in your repo — plain YAML your editor writes and git remembers. The tool is a visitor, not a landlord.
Git is the database. The store is ordinary committed files: your backlog diffs, branches, merges, and code-reviews like the rest of the repo — and outlives the tool.
Computed, never stored. Ready and blocked are a pure function of the dependency graph, so they cannot go stale and you cannot forget to unset them.
Shared by humans and agents. Built for repos where both work the same backlog — and where the tracker must not become the thing you cannot leave.
$ diarie ready ● proj-auth Add session auth high ● proj-parser Harden YAML reader medium $ diarie stats 14 tasks · 2 ready · 3 blocked · 1 stale claim
Two readers, two voices
A backlog shared by people and agents has two kinds of reader — which is why this page has two typefaces.
For humans
Your editor writes; git reviews; the diff is the changelog. There is nothing to install in your head — if you can edit YAML and commit, you already know the whole workflow.
$ for agents
claim → close → validate → ready. --json on every command, errors as machine-readable codes on stdout, and exit codes worth reading: 0, 1, 2 — with ENOSTORE when there is no store at all.
New to plain-file tracking?
Don't panic — there is less here than you think. The store is
YAML you can read, diarie init writes the first file,
and your editor and git do the rest.
Why not a classical issue tracker?
Because a classical tracker wants to be your system of record: a database, then a daemon, then a sync protocol and git hooks — and by then, leaving is a migration project. Here the record stays yours, and a tracker you can leave is a tracker you can trust.
Your editor is the write side
There is no diarie add, no close, no
assign — deliberately. A CRUD layer would make diarie
the owner of your data, and the point is that you
own it.
Claiming a task is two lines in your editor; completing it is
one — status: completed. The files are the API; git is the
audit log; diarie validate is the integrity gate.
And the reader is honest: a malformed row is represented, never silently dropped — dropping it would hide it from the human whose typo it is.
tasks: - id: proj-auth title: Add session auth status: in_progress # ← the claim agent: alice type: task priority: high deps: [proj-session] # blocked until done
Four types. Framings are labels.
“What kind of thing is this” admits one answer;
“how should I think about it” admits several. So bug,
feature, chore, spike are labels on a task —
and an epic is a task with children, not a special type.
task
A unit of work. The only type ready ever surfaces.
milestone
A structural marker. No effort, no assignment.
.diarie/tasks/*.ymldecision
An architectural choice and its reasoning. Open while in force.
.diarie/decisions/*.mddoc
Reference prose, schema in frontmatter.
.diarie/docs/*.mdA library with a bin
The pure functions are exported and fully typed — the same reader the CLI uses, importable wherever an agent or a script needs it.
import { computeReady, loadTasks } from 'diarie' const tasks = await loadTasks('/path/to/project') const { ready, blocked, needsAttention } = computeReady(tasks)
needsAttention is the third
partition, and it matters: a row whose required fields are malformed is
broken, not merely non-workable — so it is surfaced, not skipped.
The exit codes are worth reading
Point most tools at a project that tracks its work elsewhere and they print nothing and exit 0 — indistinguishable from “you have no work left.” Those are opposite situations, and conflating them is how a broken tracker gets reported as a clean sprint. So:
The answer is on stdout
An empty but present store is a legitimate answer.
You asked wrong
A machine-readable code says how: ENOSTORE,
EUSAGE, EEXIST.
It ran, and the answer is no
The store is unsound: validate found errors, or
ready --strict met a dropped row.
$ diarie ready --json --root /tmp/not-a-project { "error": "no .diarie/ store found", "code": "ENOSTORE" } $ echo $? 1
A missing store is an error, not an empty backlog — so a script can tell “tracks its work elsewhere” from “has no work left.” That distinction is the entire point.
The refusals
The non-goals are identity, not backlog. Each is firm — and carries a named revival trigger rather than being permanent by temperament.
Leaving must always be free — every refusal above exists to keep it that way.
Try it on a repo you already have
Leaving is free: uninstall diarie and your backlog is still there, in files you own.
npm install --save-dev diarie
diarie invents none of this; it applies a canon. Local-first software — you own your data, in spite of the cloud. Convivial tools — tools that preserve their user's autonomy instead of dominating them. Calm technology. Worse-is-better — the simpler thing that ships and stays legible. And the own-your-data ethos of the IndieWeb. A backlog is a small place to apply them — which is the point.