Pyxida - A Command Center Built on Obsidian and a Local LLM

Elijah Koulaxis

August 28, 2026

pyxida

For a while now I've been building something I call Pyxida (Πυξίδα, Greek for "compass").

It started as a small thing to stop losing track of my day and slowly turned into the tool I open first every morning. Todos, notes, reminders, learning queue, project stuff, random ideas that show up at midnight. All in one place.

The part I like most is that the actual backend is just my Obsidian vault. Plain markdown files sitting on my Mac. No proprietary database holding my life hostage, no "export to CSV" nonsense if I ever want out. Just files I can grep.

And it syncs to my phone, so I can throw something in from anywhere. If I don't write it down the second I think of it, it's gone. That's just how my brain works.

There's also a chat built in, running on a local LLM, so I can talk to the thing and have it actually do stuff for me. Local because everything in there is my data and I'd like it to stay that way.

Table of Contents


Why I Built It

I've tried a lot of productivity apps and something always annoyed me.

One was great at todos but terrible at notes. One had a nice calendar but didn't match how I think. One needed 15 clicks to write down a single thought. And all of them wanted my data in their cloud, in their format, forever.

Meanwhile I was already writing everything in Obsidian anyway. So at some point I figured, why not build the thing on top of what I already use?

That's basically the whole idea. My notes stay markdown. Everything else is just a nicer way to look at them.

What It Actually Does

The morning starts with a briefing. It fires automatically at 08:30 through a macOS LaunchAgent and pops up a native window. Overdue stuff first, then today, inbox, calendar, reminders, open PRs, failed CI, flagged email. There's a weekly one on Mondays too that's more of a "what did you actually do last week" review.

pyxida-briefing

I open the laptop, the window is already sitting there. No app to launch, no tab to find. Then there's the capture bar, which is where most of my input actually happens. I type a sentence, pick where it goes, and it's in the vault.

pyxida-capture

The bar reshapes itself depending on what you're capturing. Pick a reminder and you get a time and a recurrence. Pick a calendar event and you get a calendar and a duration. Pick a learning item and you get a URL field instead of a date. Same one line of input, different fields around it.

pyxida-capture-kinds

Beyond that:

pyxida-dashboard

Work stuff also lives in there. I use a devbox day to day, which means one machine covers both personal and work, and that turns out to be a great fit for something like Pyxida. Everything ends up in the same place instead of being split across two laptops and two sets of notes.

The Chat Is the Best Part

This is the feature that changed how I use the whole thing.

There's a chat where I just talk to an LLM directly, and it has tools wired into it. The model runs locally. That was the whole point for me. My todos, my notes, my calendar, the messy half-formed stuff I write at midnight, all of that is mine and I want it to stay on my machine. A local model means the thing helping me organise my life never has to ship my life somewhere else.

So instead of me clicking through a UI, I type something like:

remind me to call the accountant on Tuesday morning

and it figures out that "Tuesday morning" is this coming Tuesday, that I want a reminder out of it, and gives me back a proposal.

That word matters. It shows me exactly what it's about to create, and nothing touches my vault until I hit Execute. I've had enough fun with confidently wrong models to hand one write access to my notes.

pyxida-chat

It also reads. If I ask "what's still open on that project", it searches my existing items and answers from real data. There's a small retrieval layer that figures out what's relevant, pulls at most 30 matching items, and that's it. One model call. Casual chat skips retrieval completely so it stays fast.

It understands Greek, Greeklish, and English, which sounds like a small thing until you're typing on your phone with one hand and switching languages mid-sentence like every Greek person does.

Relative dates are handled deterministically in code before anything reaches the model. "next Thursday", "tomorrow", "in two weeks" all resolve in plain functions first. Turns out models are great at intent and mediocre at calendars.

The Architecture

Here's the shape of it:

Obsidian vault + macOS Calendar/Reminders/Mail + provider APIs
                              |
                              v
              command_center.py  (the only data interface)
                              |
                              v
              cloud_sync.py  (snapshots + command queue)
                              |
                              v
              Supabase  (snapshot + queued commands)
                              |
                              v
              Vercel web app  (phone + desktop shell)

The important rule: nothing writes to the vault except the Python CLI.

Not the browser, not the chat, not the phone. Every single mutation, whether it comes from me clicking a checkbox, from the chat, or from a script, goes through the same command with the same validation. One place to get it right, one place to fix it when it's wrong.

The sync agent runs as three locked LaunchAgent jobs on my Mac:

So the flow for anything I do on my phone is:

  1. Browser pushes a command onto a Supabase queue.
  2. The UI immediately shows it as pending, overlaid on the snapshot, so it doesn't visually revert on refresh.
  3. Within 10 seconds my Mac picks it up and runs the CLI.
  4. The CLI mutates the markdown, syncs Calendar/Reminders if needed, writes an audit entry.
  5. Next snapshot publishes the new state back up.

The browser never touches my files, my Keychain, or any provider. It only ever sees a sanitized snapshot. Mail bodies, full work notes, credentials, local paths, raw provider logs, all of that stays out of the snapshot, so the web layer has nothing to leak even if I do something dumb.

On the Mac I use a thin Tauri shell that just loads the same web app in a WKWebView, with zero IPC permissions granted to the remote content. It has no logic in it at all. Which means I ship a web deploy and my desktop app updates too, no rebuild.

Recently I also added a Commit / Revert flow for todos, because ticking three boxes used to mean three round trips through the queue and a lot of waiting. Now edits stay local until I commit them as one batch, and Revert drops me back to the last synced state.

Why Markdown Is the Right Backend

People hear "my database is a folder of markdown files" and assume it's a toy. I'd argue the opposite.

I get version history for free, because the vault is a git repo. I get search for free. I get to open any file in any editor on any machine for the next 30 years. If Pyxida disappears tomorrow, I lose a UI, not my data.

It also forces good design. Because markdown has no schema and no constraints, every rule has to live somewhere explicit, which is the CLI. That's why the "only one writer" rule exists. Without it I'd have half-written checkboxes and duplicate entries within a week.

The tradeoff is that some things are genuinely awkward. Concurrent writes, ordering, anything relational. That's exactly why the queue exists instead of letting the phone write directly. I picked the constraint on purpose and then built around it.

Why I Think This Is the Future

I don't think the interesting thing about LLMs is a chat window where you ask random questions.

The interesting thing is small tools that work on your data, in your format, with your context already loaded. An assistant that knows I have three overdue things and a PR waiting for review is genuinely useful. One that makes me explain my entire life before every question is just a search box with extra steps.

Give a model tools and a clear boundary of what it's allowed to touch, and it stops being a chatbot and starts being infrastructure. The tools are the product, the model is just the interface.

The other half is ownership, and that's why the model runs locally. My data stays my data. It lives in files I control, on hardware I own.

Pyxida isn't finished, and honestly it probably never will be. But every time it saves me five minutes or reminds me of something I would've dropped, it feels like it's going the right way.

Good enough for now :)

Tags:
Back to Home