03  ·  Ballast  ·  active
projectsabout

Sydney

03 · Ballast

A diary I can keep as files

I used Daylio, and I like that basic routine: pick a mood, tick a few activities, write something if I feel like it. Ballast keeps that shape, with the entries stored as Markdown files I can read outside the app.

The folder can be searched with grep and synced with Syncthing. There's a desktop app and an Android build. The source is private.

svelte 5tauri 2kotlinlocal-first
What it is

The bit I wanted to keep from Daylio

I kept Daylio's five mood levels: rad, good, meh, bad and awful. The activities are mine to define. Beyond that, an entry is a time and whatever I want to write.

I tend to log a morning and an evening, so several entries on the same day are normal. The diary and calendar are just two ways into those entries.

An earlier version tried to do much more. The rewrite cut it back to the diary. I'm trying to let actual use decide what gets added.

The data

What an entry looks like on disk

An example of the file format, with placeholder text rather than a real diary entry.

FIG. 1 · BallastData/
BallastData/
  entries/2026-07-27_1005.md
  activities.json    # [{ id, name, icon, archived? }]
  briefs/            # optional, written by something else
  .ballast/          # recovery journals, normally empty

--- entries/2026-07-27_1005.md ---
---
id: "entry-1fdd93a0-…"
at: "2026-07-27T10:05"
mood: "good"
activities:
  - "walk"
  - "reading"
---
Placeholder note text, kept verbatim.
The filename carries the entry's time, so listing a folder is enough to build the month index.

Moods are stored by name, which is easy to search for. Activities have stable IDs, so renaming one doesn't require rewriting old entries.

Living with plain files

The app isn't the only thing touching them

A broken entry

If an entry's frontmatter won't parse, it stays readable as text and is kept unchanged. Hand-editing a file shouldn't make the app destroy it.

The old diary

The Daylio importer writes into a new folder and verifies the result before making it visible. It refuses to import over an existing diary.

Desktop and Android

The diary rules are shared. Desktop files, Android's storage picker and in-memory test storage sit behind the same interface.

The native bits

A few Rust and Kotlin plugins handle the Android data folder, notifications and app updates.

Briefs from elsewhere

An external process can leave a Markdown brief in the synced folder. The Android app checks for it and can post a notification.

Notes for future fixes

The More screen can turn a bug or feature idea into a GitHub issue, so I can record it from the app.

Syncthing means a file can arrive while the app is open. New entries use exclusive create, and edits check the revision before saving. That helps, though it doesn't make concurrent edits impossible to lose.

The rewrite

Making it smaller

Notes from the rewrite and the October 2026 release.

  • The first version was a much larger personal research instrument.
  • The rewrite kept the entry, calendar and activity management, and removed the old experiments, protocols and job board.
  • Version 0.3.5 reached Google Play's internal testing track.
  • There is also a background-idle check. A diary sitting in the background has very little reason to keep the phone busy.

The old version is still on the pre-rewrite tag. The current repository calls the app Afterglow; the Ballast data-folder name is kept for compatibility.

Unfinished bits

What I might come back to

For now, sync belongs to Syncthing. Stats, goals and streaks were left out of the rewrite. The plan is to add things when I actually miss them.

  • Edits are checked against a revision just before they are written, but the storage providers have no atomic compare-and-swap. A writer that lands in the gap after that check can still win.
  • The last release reached Play’s internal testing track. The handover says installation on a physical phone was not observed during that session.
  • The source is private, so this page is a description of my setup rather than something someone else can reproduce from a public checkout.

Open question

I haven't decided when I'd bring statistics back. I'd rather use the diary for a while and see which questions I keep wanting to ask it.

MaterialsSvelte 5, Tauri 2, Rust, Kotlin
VintageJuly 2026 to now
StatusActive, v0.3.5
Sourceprivate
Press / for the other projects03 / 12
Index12 / 12

  • 01Tauri ExplorerMy file explorer · Rust and Svelte · notes on building it
  • 02ScrivoMy Markdown reader and editor · Typora-style live preview
  • 03BallastMy mood diary · Markdown files · desktop and Android
  • 04Quickshell barMy Hyprland bar · agent state and quota pacing
  • 05Tableau FrogData exploration · linked charts · AI experiments
  • 06LambdaQueryPython-to-SQL compiler · started in 2017, revisited in 2026
  • 07Ashen CathedralA first-person Diablo experiment · Unreal Engine 5 · paused
  • 08Brood War AIBrood War agent · imitation learning · work in progress
  • 09AutomatedSpikeMagic deck search · learned pilots · XMage experiments
  • 10Zheng Shang YouOur family card game · learning agents · playable version
  • 11EskivA game from high school · recreated during Covid · search-based bot
  • 12Intuition on the Central Limit TheoremCentral limit theorem · interactive mathematical exposition
↑↓ move↵ openesc closeTap a project to open it