blog/lifelab/Matryoshka software
Lifelab Family
Lifelab Family

Matryoshka software is the idea that you can nest increasingly capable versions of the same app inside each other. More compute unlocks more features. I want to start backwards, by describing the first, most powerful version, and then explore what gets sacrificed on the way to minimalism.

I've been building a note-taking app (current name: Lifelab, updated name pending) that exists in three versions sharing the same React frontend and a unified block API and scripting layer. The heaviest runs an Axum server with Postgres and can perform machine learning. The lightest is a PWA app working in local storage. I then propose a fourth, nano version, that lives on a USB stick without an operating system.

They all let you write notes, tag them, and look at them in daily, weekly, and monthly views.

Lifelab Max
Lifelab Max

The default, heaviest version is an Axum REST server with Postgres database. The purpose is to be hosted on a private server and be available anywhere as a personal wiki. The frontend is responsive and very mobile friendly.

It allows ingesting information via Telegram and automation via Python. You can write also code in lua, which gets executed in the rust backend. The data sent to the clients is always small enough to be snappy (about 1 screen worth of content at a time), and the computation is done in the backend with a powerful database. It can run basic machine learning models and in theory, if I scaled this up to a multi-GPU instance, it could run a local LLM. It's big, it's loud, it does a ton of things for me including this blog.

Lifelab Pro
Lifelab Pro

Lifelab pro is a desktop only, local first app. It uses the exact same frontend, but with a Tauri as app container and a sqlite database. Instead of bundling Python, it bundles a Lua interpreted and language server to make standalone development feasible. You write notes and extend the system within the same app. Everything is stored in a single database. Since Tauri embeds a rust-based mlua library, it should be fairly snappy!

The app further exposes a http server so you can script and send information into the app. On the app side, you implement lua hooks to trigger on ingestion, process the input and create blocks. I personally use this to track my tasks at work, the scriptability is a major benefit and frankly it is the most coding I do during the day.

Lost:

  • Python support. Theoretically possible to add but bundling python implies all libraries and that's a rabbit hole I don't want to go to.
  • Telegram ingest support. You can implement your own since the http server is exposed, but it is not possible to bundle together
Lifelab Lite
Lifelab Lite

You can install lifelab as a progressive web app and just use it in your browser without the tauri app. You lose native sqlite database, the lua language server, which means the coding experience will be quite a bit worse. Lifelab lite still bundles Lua extension language wia web assembly (WASM) and stores the notes in a WASM sqlite database. Unfortunately, it is at the mercy of the browser storage limits, and a single cache cleanup can just delete your content, which I felt is a bit dodgy. I am not sure you should put a critical note taking app in just LocalStorage of your browser, but you do you. Good luck.

Lost:

  • rust-powered lua interpreter with JIT
  • lua language server for development
  • proper sqlite database

Note:

  • Silverbullet is in this bucket, with a synchronization server and a fully local first PWA mode.
Lifelab Nano
Lifelab Nano

This one is hypothetical, but I envision a USB-stick like device (maybe raspberry pi zero?) that you plug in. This boots the device and turns on the http server which is exposed via lifelab.local in your browser. Opening the website loads the react frontend, so you get the same visual experience as in Lite.

The lua computation is done on client (WASM Lua code), but the database is on the stick itself. I envisioned a brutally minimal, operating system free device that only supports a HTTP server on loadup and a sqlite database. After pushing the frontend to the users browser, it just acts as a database for queries. Whatever lua code is written will have to query the database via REST.

Since it has to push data on load, we need to minimize the initial package as much as possible. Codemirror 6 is about 500KB and a strict requirement. The next biggest javascript packages are mermaid (diagram package, about 700KB) and katex (for latex rendering, around 400KB), those two will have to go to make the experience as instant as possible.

This one is extremely portable (just plug your note taking stick anywhere and get the fancy app you are used to) and I liked the idea of an embodied software. The sole purpose of the stick is for your notes, with storage and your customizations. No operating system, no SSH, no vim, no cruft. I wanted it to just instantly boot into the http the moment you plug in. Maybe it would need some authentication/encryption and we need to consider NAND wear and tear, but how cool is carying your notes with you with the app to view them?

Lost:

  • mermaid diagram support
  • latex rendering support
Final chart
Matryoshka software?

I like this frontend a lot, and I envisioned a lot of scenarios where to reuse it. As we go down in supported computation we need to cut a lot of features out, but the cure experience of writing notes, organizing them via tags and visualizing them is still there. I am not sure when a person would rather plug in a stick to use a slow database than visit a website and authenticate, but I found the idea intriguing, especially with cutting down the stick to the bare essentials!

Lifelab rejects
Lifelab rejects

I implemented further versions and prototypes of this concept, but I mostly abandoned them, including:

Database-free lifelab with .org files

Since I use a repository pattern for all block and page operations, I can easily replace the sqlite/REST repository with a pure file based one. In this case I selected .org format, because my blocks are naturally org headlines with property drawers. Markdown is not feasible due to the amount of metadata each block has (it would be ugly as sin) and pure json doesn't really do prose well. Org files were really readable and I like them! All versions of lifelab support exporting to org file, but in this case it also used files as default. I had to implement some scan-based version of block query and search, but it kinda worked. I still feel it is stupid.

Lifelab CLI

When I first started lifelab I had a CLI version I really liked because ratatui is really beautiful and easy to use. As I developed this further and found a database schema I liked, I mostly just iterated on the frontend and mobile experience and CLI fell behind and couldn't support all the features anymore. The backend now is fairly lean and most of the logic would have to be ported from typescript, which is just too much work to launch every time I add something. For a single person app this becomes unsustainable and I had to cut it.

Powersync-powered hybrid-offline Lifelab

I envisioned a local first (Lifelab Pro) web app that works offline, but still syncs with a database (Lifelab Max) whenever free so I can work in different modes seamlessly. Powersync allows synchronizing your local sqlite with a remote postgres database, which is exactly what I had. To do the vice versa, the client has to send a update to the server and the server has to handle it including conflict management, but it is definitely doable.

I got it to work and I do think Powersync is incredibly easy to use, but I ran into a lot of edge cases where Python blocks only run on server, lua blocks can run on both server and client and it became a mess to figure out what runs where.

The synchronization itself I felt was very reliable, especially when I added individual block versioning (each update is added to the version history, making it easy to merge and revert bad state.) This was a major incompatibility with the .org version, because you can't do block level versioning on markdown text! Certain operating systems allow snapshotting but it is not exposed to apps. More on this later.

Lifelab E-Ink

I like eink a lot and I thought a simple device with a keyboard would be great to write notes (..or this blog..) but I quickly abandonend it since my phone is always with me and I should not needlessly spend money on gadgets. The idea was a simpler, cut down version of the frontend as PWA, optimized for high latency monoschrome screen (bit of a combination of lifelab CLI and lifelab Lite)

Lifelab glasses

I thought of buying smart glasses with a display (like Even Realities) that support augment OS, a typescript based app that runs on your phone and on the glasses to display stuff. It seemed fairly easy to implement and very compatible, but I hadn't figured out the controls that would be satisfactory so I put the idea on ice. Maybe with smart rings and mini joysticks I can revisit this.