← Side projects
2026–Present Live

Soma Tracker

Built my own tracker, then taught a bathroom scale to talk to it.

Solo build — architecture, code & ops.

There's no shortage of apps for tracking a workout or a weigh-in. What changed isn't the market — it's the cost of building one myself: with AI-assisted development, going from "exactly what I want" to a working app stopped being a luxury. Soma Tracker was usable the same evening I started it, and has grown by a feature a week since. The sequel came a month later: the vendor app for my bathroom scale was friction I didn't need, so a second-hand Raspberry Pi now listens for the scale's own Bluetooth broadcast and hands each reading to an AI assistant, which decides whether it counts and logs it — no phone, no app, no typing.

  • .NET 10
  • SQLite
  • Python
  • Raspberry Pi
  • Bluetooth LE
  • Tailscale

Real screenshots of it running, not mockups.

Soma Tracker on a phone: today's weight, the smoothed trend and a 90-day chart
Weight, with the trend line that actually matters — the scale fills this in on its own.
Soma Tracker on a phone: a workout with blocks, per-side exercises and timed holds
A workout: blocks, per-side exercises, timed holds. Tap play and it runs the session.
Soma Tracker on a phone: the weekly training plan with today highlighted
The week. Each day knows its type and the workout to launch.
  • Weight logging with a trend I can trust: an exponentially weighted average that decays by elapsed days, not by number of readings, so a week without a weigh-in doesn't fake a jump.

  • A guided workout player — blocks, sets, timed holds — that runs the session so I don't have to think mid-set.

  • A weekly plan and goals, weight or exercise, with progress calculated live.

  • Weigh-ins arrive on their own: a Raspberry Pi hears the scale's Bluetooth broadcast, a small relay on my server logs it, and an assistant decides whether to store it — one weigh-in a day, the morning one.

  • My assistants use it without an integration: I say "ran 5k this morning" in a chat and it lands in the tracker; I ask how the month is going and the answer comes from the database itself.

  • Features arrive on my schedule: an idea mid-workout is a sentence to Claude Code that evening, and most of them are in the app before the next session.

The choices I made, and what they cost.

  1. ASP.NET Core minimal API, no ORM

    Decision

    One Program.cs, raw SQL via Microsoft.Data.Sqlite — one endpoint per resource, no controllers or DI ceremony I don't need.

    Why

    Nothing between me and the database that I have to maintain, and the agent I build with reads the same SQL I do.

  2. SQLite in WAL mode, designed agent-native

    Decision

    The database is safe to read from outside while the app keeps writing to it.

    Why

    An assistant can query it directly for reads with no API required — the integration surface for "connect this to my other tools" is a file, not a contract.

    Trade-off

    Writes always go through the API, never a raw INSERT — it recalculates the weight trend, and a direct write would silently skip that.

  3. Vanilla-JS PWA, no build step

    Decision

    index.html, app.js, style.css and a service worker. No framework.

    Why

    Installs to the home screen, works offline, and the edit-reload loop stays as short as possible when a feature idea shows up mid-workout.

  4. On my own VPS, behind my own network

    Decision

    A systemd service on my server behind Caddy, reachable only over my tailnet — no public exposure, no accounts, no subscription.

    Why

    The network is the perimeter, so there is no auth layer to build or maintain for a single-user app. It also puts the tracker on the same machine as my agentic assistants, which is what makes the next decision possible.

    Trade-off

    It's mine to operate: backups, updates and uptime are on me, and there is nobody to email when something breaks.

  5. Dumb edges, smart middle (the scale integration)

    Decision

    The Pi and the relay that connect the scale carry no credentials and no rules — they turn a Bluetooth broadcast into one message and hand it off.

    Why

    The judgement — one weigh-in a day, a plausible range, what counts — lives in the assistant, in a paragraph of plain prose. Changing a rule means editing a sentence, not reflashing a device.

What custom actually buys you isn't the features — any decent app has features. It's that the data is a file on a machine I own and the API is a port on localhost, so my assistants need no plugin, no webhook and nobody's permission to use it: they read the database directly and write through the API. It's that a feature idea mid-workout is a sentence to Claude Code that evening, not a vote on someone's backlog. And it's that the data outlives the app — months of sessions in one file I can copy, query or hand to whatever I build next. That's also why the scale took days rather than a redesign: when the pieces are your own, the next problem is close to free to wire up.