← back to the office

Alien Tasks and Alien Habits: the backend of my life

Aug 2026 · self-hosting, CalDAV, orchestration

After the Google Exit my tasks and calendar live on my own CalDAV server. But a server is not a product. I needed two small apps on top (one for tasks, one for habits) plus the glue that keeps my kanbans, my phone and my browser on the same data.

The stack

Everything is a small systemd unit on two machines, talking over HTTP and CalDAV:

mini (Win Mini, 100.95.188.29)        jacinto (Pi, 100.99.112.42)
radicale        :5232  CalDAV server  alientasks      :5233  tasks UI
beaverhabits    :8081  habits tracker alientasks-tail :5233  socat
divalien-kanban.timer (every 30 min)   tailscale serve       HTTPS
  └─ sync_kanban_to_caldav.py

The phone talks to Radicale through DAVx5: the Tasks app for todos, Etar for the calendar. The browser talks to the same server through alientasks. The kanbans in Obsidian sync into it every 30 minutes. One source of truth, three kinds of clients.

Alien Tasks and Alien Habits backend stack
Two machines, one calendar contract, three kinds of clients.

One source of truth

Radicale is a minimal CalDAV server and the only place where tasks and events actually live: eve/tasks/ (608 VTODOs), eve/work/ (4,531 events), eve/calendar/ (personal). The apps do not own the data; they are views.

  • Phone: DAVx5 + Tasks app. Adding a task on the go writes a VTODO straight to the server.
  • Web: alientasks (on jacinto), a small Python app that groups the VTODOs by CATEGORIES and flips STATUS when you tick a box.
  • Kanbans: a systemd timer wakes every 30 minutes and runs sync_kanban_to_caldav.py, turning Obsidian kanban rows into VTODOs (and back).

The habit tracker

Habits are not tasks, so they get a different app: Alien Tracker (a fork of Beaver Habits), a Python/NiceGUI app on the mini at :8081. No login: a trusted-email drop-in authenticates the single user. Habits live in SQLite as a JSON blob, one row per habit with its records, tags and streaks. Deliberately separate from CalDAV, because a habit is not a to-do.

The glue

There is no orchestrator app, no message queue. The orchestration is systemd:

  • radicale.service and beaverhabits.service run on the mini.
  • alientasks.service runs on the Pi (bound to loopback) with a socat unit exposing :5233 on the tailnet.
  • divalien-kanban.timer fires every 30 minutes with Persistent=true, so a sleeping machine catches up on wake.
  • Tailscale Serve gives HTTPS names instead of raw ports.

The same instinct as my data pipelines: idempotent syncs, a timer instead of a daemon, and verification after every write.

What it taught me

  • The source of truth is separate from the UI. CalDAV is the contract; the apps are replaceable views.
  • Standard protocols beat integrated apps. CalDAV means my phone, my browser and my kanbans all interoperate for free.
  • The phone is just another client. When I add a task on the go, it lands in the same store as the kanban sync.
  • systemd is enough orchestration. Timers, units and socat cover a two-machine personal backend without a single new dependency.

The reliable choice, again

Two machines, one calendar contract, three kinds of clients, and everything owned. The backend of my life is boring on purpose: the boring parts are the ones that keep working while I sleep, and catch up when I wake up.