DEV Community

Cover image for I Ditched My Fitness App for a Folder of Markdown Files (Spoiler -It's Better)
Javier Ramírez
Javier Ramírez

Posted on

I Ditched My Fitness App for a Folder of Markdown Files (Spoiler -It's Better)

Let me tell you about the exact moment I knew I was over fitness apps: I opened one to log my workout, and it asked me to rate my mood in an emoji scale before it would let me type in the proper amount of lbs being worked. I didn't like it. Not. One. Bit.
I'm fickle.
Sue me. This happens as you age.
I just wanted to write down a number.

So I did what any reasonable human being does when a piece of software annoys them: I deleted it and rebuilt my entire training log in a text editor. Specifically, in Yamlink — a VS Code extension that turns plain Markdown notes into a live knowledge graph. Fitness was not quite the motivation behind its development built for notes and knowledge work. But, in about an hour, with just this plugin and zero mood-tracking emojis, I was pretty satisfied with what was done.

Here's how, and why I think it's genuinely good — not "good for a hack," just plain good.

Step 1: A workout is just a note with opinions

Yamlink's whole model rests on one idea: every note gets an id: and a type: in its YAML frontmatter, and that's basically it. No schema to define up front, no "create a Workout object" ceremony. You just... write the file. One tiny set of properties can turn your vault in an operational knowledge vault. And you can take it in any direction you want.

---
id: workout-2026-08-03
type: workout
date: 2026-08-03
exercise: back squat
sets: 5
reps: 5
weight: 185
program: "[[program-strength-block-2]]"
---

Felt heavy today. Left knee a little cranky on set 4.
Enter fullscreen mode Exit fullscreen mode

That's it. That's the whole process. No ads, app login, no waiting 25 seconds before being able to log your work. It's a text file sitting in a folder I own, that'll still open in the Cyberdyne computers we'll own in twenty years, because it's Markdown, not a proprietary blob in someone else's database/platform.

Step 2: your log becomes a live, editable table, not a static list

Here's where it stops being "just notes" and starts being genuinely useful. Drop a !view block into a note and it renders as a real, interactive table pulling live data from every workout note in the vault:

!view workout sort date desc
Enter fullscreen mode Exit fullscreen mode

That's not a static export. It's a live query. Change a value in the table, it writes straight back into the actual .md file. No "sync," because there's nothing to sync — the table and the file are the same data, just two ways of looking at it.

Want to see if your work is yielding results, or if you're just telling yourself a nice story?

!view workout where exercise = "back squat" sort date desc
Enter fullscreen mode Exit fullscreen mode

Run it, then flip the same result set to a scatter plot from the View Panel's own toolbar — no extra syntax, just a layout toggle sitting right there. Real chart, real data, zero "connect your Watch to unlock trends" poophousery.

Step 3: link your workout to your program, because context matters

This is the part that made me actually feel something. Yamlink treats [[wikilinks]] as first-class graph edges — write [[program-strength-block-2]] anywhere and it's a real, navigable connection, not a string that happens to look like a link.

So my workout notes link to the program note they belong to, my program note links to a goal note, and suddenly I've got an actual knowledge graph of my training instead of a spreadsheet pretending to have structure. Open the graph view and you can see the shape of a training block — which workouts belong to which phase, at a glance, rendered as an actual graph, not a filtered list dressed up with a fancier font.

Step 4: let the graph do the counting for you

Yamlink has a small set of computed fields the engine tracks automatically, no formula required — _inbound_count being the one I didn't know I needed. It's just "how many other notes link to this one." Point it at my program-strength-block-2 note, and it's quietly counting every single workout I've logged against that block.

I never tally sessions. I never have. The graph already knows, because it's just counting real edges — the same links I wrote anyway to give my workouts context in Step 3, now doing double duty as a running total I didn't have to ask for.

Not math. Not AI. Just an honest count of the connections that already exist.

Step 5: the calendar knows when you skipped leg day

Every note with a date: field just... show up on Yamlink's built-in calendar, automatically. No separate "log this workout in the calendar too" step, because there's only one copy of the data, and everything reads from it.

And here's the detail I'm really loving: Yamlink has a Vault Health feature that flags notes nobody's touched in a while. It doesn't do this with a cutesy notification like "Hey champ, ready to go get the day?! 💪" — it just quietly, honestly surfaces "this hasn't been updated in 9 days" as a structural fact about your vault. No guilt-tripping of any kind. No streak-shaming push notification at 8pm on a Sunday when you felt like having a treat. Just cold, accurate silence when you're on track, and an honest flag when you're not. Somehow, I found that more motivating than the app ever was.

Step 6: it's honest about what it isn't

I want to be extremely real, because the rest of this article has been fun and kinda smug in my honest opinion: this is not a mobile app. There is no fancy iPhone experience here. Yamlink lives in VS Code (and a genuinely nice terminal UI called Conduit, if you're the type who'd rather log a set from a terminal than unlock your phone — and if you're reading a dev magazine, you know exactly who you are). If your ideal fitness tracker experience is thumb-typing while your quads are trembling mid-set, this isn't that, at least not yet.

What it is: a fitness tracker that's actually a side effect of a much more general tool — one that treats "workout" as just one possible shape a note can take, alongside "book I'm reading," "person I met at a conference," or "recipe I keep ruining." The frontmatter doesn't care what domain you point it at. It just wants a type: and some fields.

The actual pitch

Every fitness app I've used eventually turns into a subscription, a walled garden, or both. And honestly, I can live with that. Your training history — actual, real information about your actual, real body — ends up owned by a company whose business model depends on you not leaving. I can live with that too. But then, as Yamlink kept evolving, I figured I could flip the app experience to a folder of files on your own disk. You can grep it. You can git log it. You can open it in Notepad in the year 2040 and it'll still just say what it says.

Yamlink was not built to be a fitness tracker (at all). That's kind of the point — a tool that adapts to what you structure, instead of a tool that structures you into whatever the product team decided this quarter, is a genuinely different kind of software. Turns out "flexible knowledge graph" and "training log" are the same shape wearing a different type: field.

Also, no emojis. I cannot stress enough how much that matters to me at my advanced age.

Top comments (0)