Chronicle logo over a blurred screenshot of the Immich timeline

2026-mar-06 • updated 2026-mar-07

Chronicle: Building My Own Recall for Linux + Immich

From a sketchy shell script to a privacy-first Rust timeline tool.

Technologies: Rust, Linux, Immich, Systemd, CLI
Link: Source Code

Why I Built Chronicle

Chronicle started with a simple thought: Windows' Copilot Recall is a genuinely useful idea.


Being able to verify what I was doing at a specific point in time sounded awesome. I could prove I submitted or worked on a school assignment, recover context from a random afternoon, and generally have much better memory for my digital life than I usually do. But... I run Linux. Not only that, but even if Microsoft eventually brought Recall to Linux, I wouldn’t want to use it. I don’t trust Microsoft with that level of data, and I don’t want to give them that much insight into my behavior.


So I decided to build my own version: local-first in spirit, self-hosted for storage, and under my control from end to end.

Humble Beginnings

The original project was called "Recall" (yes, very creative naming), and it was a classic just-make-it-work MVP:


  • a shell script
  • screenshots via scrot (I used to run X11 on Mint)
  • fixed capture settings
  • direct upload to Immich with curl
  • and a hard-coded API key (yikes)

I wrapped it with a tiny systemd upload service and timer and called it a day.


It was rough, but it was useful: capture the screen periodically, upload the results to Immich hourly, and let Immich do its thing.

Why Immich Was a Big Part of the Vision

One of the key motivations from day one was Immich.


I already trusted it, I already liked the self-hosted model, and I really wanted to piggyback on its ML features for search and organization. Instead of building a giant timeline backend from scratch, I could focus Chronicle on collection, metadata, and reliability — and let Immich handle media management and discovery.


That architecture decision still feels right. In the future, I would actually prefer to develop my own timeline backend instead of relying on Immich (for deduplication, for example), but that’s a much bigger project.


Chronicle timeline in Immich
Chronicle timeline in Immich

X11 Was Easy, but Wayland Humbled Me.

At the time, I was using X11, so the MVP was quick to get running. Then, in my infinite wisdom, I switched to TuxedoOS on Wayland, and everything broke.


I still wanted Recall of course, and since I was planning to start a much larger Rust project in the near future, I took this as a training ground: rewrite Recall in Rust, do it properly, and learn the ecosystem.


I underestimated how much work this would be. I had to dig into display-server differences, fallback capture strategies, system integration details, IPC patterns, and all the “small” edge cases that make long-running tools reliable. I also had to learn Rust deeply enough to stop fighting it and start using it well (thank you, rustfmt!).


It was a lot, but that challenge was the point.

From Script to Real Product

Chronicle today is much more than the first script.


It supports multiple capture paths so it can run across modern Linux environments:


  • Wayland-native capture when available
  • XDG portal fallback
  • X11 fallback for older or specific setups.

On top of that, it includes adaptive capture logic to avoid saving/uploading near-identical frames, which is huge for storage and bandwidth over long timelines. In practice though, even with my four-monitor setup producing massive images, .webp compression makes things pretty light: a full year of daily 8-hour capture every 30s only takes about 60 GB in Immich, which is manageable for my self-hosted setup.


Then there’s reliability work I didn’t have in v0: local queueing, retries, and operational visibility through CLI health/status commands.


Chronicle setup wizard
Chronicle setup wizard


The setup flow also grew from “edit a script and pray” to a wizard-based experience that handles the important parts in a guided way. One of my favorite upgrades is security hygiene: instead of hard-coded credentials in scripts, Chronicle now uses a keyring API key handler, and safer auth flows.


That sounds obvious, but it took me building the wrong version first to really care about doing it right.

Pause, Resume, and Control

For when I need to leave my PC for hours for, say, rendering a 3D animation, I don’t want Chronicle to capture every minute of that. For these moments, Chronicle includes pause/resume behavior so you can intentionally stop capture when needed.


Pause and resume in Chronicle
Pause and resume in Chronicle


Similarly, status and health commands make the system transparent. If this tool is running in the background all day, you should be able to verify what it’s doing without guesswork.


Status command output
Status command output


Health command output
Health command output

Preparing Me for Bigger Rust Work

Chronicle is a technical project, but for me it’s also personal infrastructure. It helps with practical things, like proving work timelines for school, recovering context after interruptions, or understanding how time was actually spent on a day that felt chaotic.


But it also represents a principle I've come to care about more and more recently: if a tool handles sensitive behavioral data, ownership and trust boundaries are not optional details. I originally framed this rewrite as Rust practice before Hyprcontact, but Chronicle became a serious project in its own right, and a much better Rust teacher than any toy app could have been.

Conclusion

Chronicle exists because I wanted a useful memory tool without outsourcing trust. If that resonates with you — especially if you’re already running Immich and care about local control — Chronicle might be useful in your setup too.


Source and releases: