Red notes become tasks: Jolla GTD goodness.
One of the things I was looking forward to about the Jolla was that it’s a proper Linux machine. Small integrations that would be awkward on most phones can be built using entirely ordinary Linux tools.
Today I finally tried it. In a few minutes, I closed a small but persistent gap in my task-management system: red notes on my phone now become Taskwarrior inbox items automatically.
I use a GTD style system. One of the most important parts of any GTD system is a trusted inbox where you can capture stuff that occurs to you, wherever you are, allowing you to carry on with your day knowing you can process it later. I've used a bunch of stuff before: reminders in Slack, Google Keep, but there's always a manual element.
Notes typed into the Jolla's stock Notes app now turn into tasks in my inbox, automatically, and sync home. Here's the setup, in enough detail that you could replicate it if you've got a Jolla and a taskwarrior sync server already running.
One honesty note before the code: I described what I wanted and Claude wrote the scripts and systemd units. I tested the code and made the design decisions, but I'm not going to present this as unaided. Without that assistance, this small convenience probably wouldn’t have been worth spending a Sunday morning on, and therefore wouldn’t exist.
The context, briefly
I run GTD in two pieces: taskwarrior holds every actionable item, and a vimwiki-based wiki displays them via taskwiki viewports, so my dashboard is a text file in Neovim. Captured-but-unclarified stuff carries an +in tag. That's the inbox. Taskwarrior 3 syncs replicas through a self-hosted taskchampion-sync-server, which in my case runs on a machine at home, reachable over Tailscale. That server and a working desktop client are the prerequisites this post assumes.
Step one: make the phone a sync replica
Taskwarrior 3 runs happily on Sailfish. With it installed, the phone just needs the same sync credentials as any other replica, in ~/.taskrc:
sync.server.origin=https://your-server:8088
sync.server.url=https://your-server:8088
sync.server.client_id=<same uuid as your desktop>
sync.encryption_secret=<same secret as your desktop>
Why both origin and url? Version gotcha: taskwarrior 3.0.x only reads sync.server.origin; the key was renamed to sync.server.url in 3.1. My phone has 3.0.2, my desktop is newer. Setting both means it keeps working when the package updates. If task sync says “No sync.* settings are configured” despite your config looking right, this is why.
First task sync on the phone pulled down my whole task list. Same list on the desk and in my pocket. That alone was worth it.
Step two: the Notes app becomes a capture tool
Typing task in "some thought" in a terminal on a phone is friction, and friction kills capture habits. The Jolla's Notes app, on the other hand, is two taps away. So: a small job watches the Notes database, and any note I've coloured red gets drained. Each non-empty line becomes one +in task, the note is deleted and task sync pushes it home.
You can change the colour in the script but it made sense to me to have a specific colour to match rather than just drain everything, so I can keep actual notes and shopping lists in my phone without them disappearing. New notes are assigned different colours automatically, so making something a task is a deliberate step: I change that note to red.
The Notes app stores everything in a single sqlite database with a simple schema: notes (pagenr INTEGER, color TEXT, body TEXT). It's in ~/.local/share/com.jolla/notes/QML/OfflineStorage/Databases/SOMEHASH.sqlite
The filename hash may differ per install, so check rather than copying mine.
The script
~/bin/notes2inbox.py. Sailfish ships python3 with the sqlite3 module, so there are no dependencies at all:
#!/usr/bin/env python3
"""notes2inbox -- drain RED Jolla Notes into the taskwarrior inbox (+in).
Triggered by notes2inbox.path (inotify on the Notes sqlite). Only notes
coloured red (#cc0000) are captures: each non-empty line becomes one +in
task, then the note is deleted and task sync pushes to home. Other colours
are durable notes and never touched. Ordering add -> delete -> sync means
the worst failure is a duplicate inbox item, never a lost capture.
Every run ends with task sync, even when there are no red notes, so the
daily timer (and the run re-triggered by our own deletes) retries any
backlog left by a sync that failed offline.
"""
import sqlite3
import subprocess
import sys
DB = ("/home/defaultuser/.local/share/com.jolla/notes/QML/"
"OfflineStorage/Databases/8b63c31a7656301b3f7bcbbfef8a2b6f.sqlite")
TASK = "/usr/bin/task"
INBOX_COLOR = "#cc0000"
def main():
db = sqlite3.connect(DB, timeout=10)
rows = db.execute("SELECT rowid, body FROM notes WHERE lower(color) = ?",
(INBOX_COLOR,)).fetchall()
captured = 0
for rowid, body in rows:
lines = [l.strip() for l in (body or "").splitlines() if l.strip()]
ok = True
for line in lines:
r = subprocess.run([TASK, "rc.verbose=nothing", "add", "+in", "--", line])
if r.returncode == 0:
captured += 1
else:
ok = False
print(f"task add failed ({r.returncode}): {line!r}", file=sys.stderr)
if ok:
db.execute("DELETE FROM notes WHERE rowid = ?", (rowid,))
db.commit()
if rows:
print(f"captured {captured} item(s) from {len(rows)} red note(s)")
return subprocess.run([TASK, "rc.verbose=nothing", "sync"]).returncode
if __name__ == "__main__":
sys.exit(main())
The trigger: inotify
I didn't want this to have to keep waking up and polling and the answer is a systemd path unit; an inotify watch on the database file. Nothing runs at all until the file actually changes. The pieces, in ~/.config/systemd/user/:
notes2inbox.path:
[Unit]
Description=Watch Jolla Notes DB for new captures
[Path]
PathModified=/home/defaultuser/.local/share/com.jolla/notes/QML/OfflineStorage/Databases/8b63c31a7656301b3f7bcbbfef8a2b6f.sqlite
Unit=notes2inbox.service
[Install]
WantedBy=default.target
notes2inbox.service:
[Unit]
Description=Drain Jolla Notes into taskwarrior inbox
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /home/defaultuser/bin/notes2inbox.py
notes2inbox.timer — a daily catch-up in case a filesystem event is ever missed, or a sync failed while Tailscale was down:
[Unit]
Description=Daily catch-up for notes2inbox (missed events / failed sync)
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
Then:
systemctl --user daemon-reload
systemctl --user enable --now notes2inbox.path notes2inbox.timer
Does it work?
Yes, and satisfyingly fast. Write a red note, and by the time you've put the phone back in your pocket the note has vanished from the app and the task exists. The desktop sees it on its next task sync, and my wiki's inbox viewport picks it up from there without any extra plumbing. Taskwiki is just displaying the +in tag.
Caveats if you copy this:
- One task per line, so a red note can batch several captures.
- The
--intask add +in -- <line>makes taskwarrior treat the whole line as description text. Without it, a captured thought containingdue:fridayor+somethingwould get parsed as task attributes. - Ordering is add → delete → sync. If the phone is off-network,
task syncfails harmlessly and retries later. - Red notes get deleted. The app is a capture buffer for red, durable storage for the other eight colours. Don't colour your shopping list red.
I've literally just turned this on, and it's Sunday, so I've not really used it much but I'm looking forward to seeing how useful it becomes the next time I process my inbox at my desk!