6 Years, Counted by a Text File: Milestones Without an App
Every habit and streak app wants an account, a subscription, and a daily tap to keep your streak. I replaced all of them with one line of…
6 Years, Counted by a Text File: Milestones Without an App
Every habit and streak app wants an account, a subscription, and a daily tap to keep your streak. I replaced all of them with one line of plain text and a date. It has counted 2,296 days and never once asked me to check in.
The thing streak apps get wrong
Open any habit or streak tracker and the deal is the same: make an account, maybe pay monthly, and — this is the part that grates — tap every day to keep the streak alive. Miss a day and the app scolds you, resets the number, guilts you with a notification. The streak isn’t really tracking your life; it’s tracking your engagement with the app.
That’s backwards. The fact that I stopped drinking on a particular morning in 2020 is true whether or not I open an app today. The date happened. It doesn’t need maintaining. It needs remembering — and a little arithmetic.
So I stopped tapping. I write the start date down once, in plain text, and let the computer do the counting forever.
One line and a date
A milestone, in my system, is an org-mode heading with a single property — the day it started:

That’s the whole record. A title, a tag to group it, and :STARTED:. I never touch it again.
Capturing one takes a few seconds — a capture template prompts for the date and writes the skeleton for me:

Change default capture logic in emacs
![Capture [m]](https://miro.medium.com/v2/resize:fit:1400/1*CxheG_2YBTMeBPZDzEwihg.png)
Capture [m]
Hit the capture key, type the title, pick the date, done. No “log today” button, because there is no today to log — the only fact that matters is the start.
Where it comes alive: the timeline view
A start date on its own is just a fact in a file. The magic is a small agenda view that reads every milestone and turns each date into a living period — years, months, days, and the running total since:
![Before click [m]](https://miro.medium.com/v2/resize:fit:1400/1*mJPYFpoMnOa57bUYp1j3ew.png)
Before click [m]
![Agenda [m]](https://miro.medium.com/v2/resize:fit:1400/1*Vojg8s8zGG0CBPLv_SQeew.png)
Agenda [m]
Every time I open it, the numbers have advanced on their own. Nothing was tapped, nothing was confirmed. The view simply does today − started for each line and prints the elapsed time. The phrasing matters to me: not streak: 2296 — a cold score that implies fragility — but 6 years, 3 months, 15 days, a span of life that’s simply accumulating.
And it’s not only for quitting things. I track arrivals too — the day cycling entered my life, the day I started swimming, the day a tool I love showed up. Same mechanic, opposite sign: instead of how long since I stopped, it’s how long I’ve been doing this. A milestone is just a date that means something, and the view treats them all alike.
A milestone can carry more than a date
The heading is the minimum, not the maximum. Because it’s just org, a milestone’s body can hold anything — a note on why it mattered, a link, a photo. One of my older ones is the day I pulled every label off my keyboard and forced myself to touch-type blind (Dvorak, blank keycaps, no glancing down). I dropped a picture of the bare keys right under the heading:

In the timeline it stays a tidy one-liner with the running count — 2y 8m 14d and climbing. Press RET on that line and the note opens with the photo inline. The counter stays clean; the context (and the image) is one keystroke away — and the picture is just a file sitting next to the text, not locked inside an app’s database.

Why plain text wins here, specifically
I’ve written before about **I Spent 9 Years in OmniFocus. Then I Switched to a Text File. Milestones are the purest example of why it’s worth it:**
- No subscription, no account. It’s a file. There is nothing to pay for and no vendor who can sunset the app and take my dates with it.
- Completely private. My sobriety date, the things I’ve quit, the things I’ve started — none of it is on someone’s server being mined. It lives in a file I sync myself.
- No daily ritual, no guilt. A streak app breaks if you forget to open it. A date can’t be broken by forgetting — it already happened. Set it and walk away.
- It outlives every app. These records are years long. The only format I trust to still be readable in another decade is plain text. An app’s database isn’t a promise; a .org file is.
- It’s mine to shape. Want to group milestones by tag, sort them, show only the big ones, change streak to years, months, days? It’s a few lines of config, not a feature request to a company.
The whole point in one sentence
A milestone tracker shouldn’t be a thing you use. It should be a thing you set once and forget, that quietly keeps counting while you get on with living. A date in a text file does exactly that — for free, in private, forever.
The capture template and the timeline view both live in my dotfiles — [https://github.com/maxclax/dotfiles]. Take what’s useful, and go write down a date that matters.
메타데이터
- post_id
- e3e54723f9bc
- slug
- 6-years-counted-by-a-text-file-milestones-without-an-app-e3e54723f9bc
- url
- https://medium.com/@maxclax/6-years-counted-by-a-text-file-milestones-without-an-app-e3e54723f9bc
- canonical_url
- https://medium.com/@maxclax/6-years-counted-by-a-text-file-milestones-without-an-app-e3e54723f9bc
- author_url
- https://medium.com/@maxclax
- status
- ok
- fetched_at
- 2026-06-15 20:49:13