<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Pimalaya blog</title>
    <link>https://blog.pimalaya.org/</link>
    <description>News from Pimalaya, an ambitious project that aims to improve open-source tools related to personal information management.</description>
    <language>en</language>
    <atom:link href="https://blog.pimalaya.org/feed.xml" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Tue, 11 Aug 2026 00:00:00 GMT</lastBuildDate>
    <item>
      <title>Another year with NLnet</title>
      <link>https://blog.pimalaya.org/another-year-with-nlnet/</link>
      <guid isPermaLink="true">https://blog.pimalaya.org/another-year-with-nlnet/</guid>
      <pubDate>Tue, 11 Aug 2026 00:00:00 GMT</pubDate>
      <description>Pimalaya is funded for one more year through the NGI Zero Commons Fund. Here is the direction: consolidate the libraries, standardise pimdir, generalise sync, cover more domains, and ship better interfaces.</description>
      <content:encoded><![CDATA[<p>Pimalaya gets <strong>another year of support, from 2026 to 2027</strong>, through the <a href="https://nlnet.nl/thema/NGI0CommonsFund.html">NGI Zero Commons Fund</a> of the <a href="https://nlnet.nl/">NLnet foundation</a>, part of the European Commission&#39;s Next Generation Internet initiative. The entry is <a href="https://nlnet.nl/project/Pimalaya-pimdir/">Pimalaya pimdir</a>.</p>
<p>This is not the first time. Pimalaya has been sustained by NGI programs for years, and every one of those years turned into libraries, CLIs and apps that anyone can read, fork and reuse under a free licence. This one comes with a theme: <strong>a filesystem standard for PIM resources</strong>, and the work around the rest of the stack that makes such a standard worth having.</p>
<p>What follows is a <em>direction</em>, not a roadmap. The detailed plan is yet to be written.</p>
<h2>Consolidating what already exists</h2>
<p>The least glamorous part of the year, and probably <em>the most valuable</em>.</p>
<p>Pimalaya is by now a fairly wide set of low-level Rust libraries: protocol clients (io-imap, io-smtp, io-jmap, io-webdav), local formats (io-maildir, io-m2dir, io-vdir), provider APIs (io-gmail, io-msgraph, io-gcal, io-people), the plumbing they all sit on (io-http, io-oauth, io-proxy, io-pim-discovery), and the content models (vcard-rs, ical-rs).</p>
<p>They share one architecture: <strong>I/O-free coroutines</strong>, state machines that hold the whole protocol logic and perform no I/O themselves, plus a thin reference client that services their requests. It is what lets the same IMAP code run in a blocking CLI, in an async daemon, and behind a JNI transport on Android <em>without a rewrite per runtime</em>.</p>
<p>That set is already solid. What it needs now is not more surface but <strong>more depth</strong>: stable published APIs, real documentation on docs.rs, test coverage that means something, fewer half-migrated dependents, and releases that consumers can actually pin. Consolidation is what turns a pile of promising crates into a stack somebody else can build on, and that is the point of building it in the open in the first place.</p>
<h2>pimdir, a standard for PIM on disk</h2>
<p>The named deliverable. <a href="https://github.com/pimalaya/pimdir">pimdir</a> is a specification for how personal information lives on a local disk: mail, contacts, events, notes, tasks, <strong>one store, one format</strong>.</p>
<p>The existing conventions each solve one domain: Maildir for mail, vdir for contacts and calendars. They are file-per-item layouts, and that shape has known limits. Listing a mailbox means opening thousands of files. Filenames carry state, so a flag change is a rename. Case sensitivity, forbidden characters and path length limits differ per filesystem, so a store that works on Linux is not automatically a store that works on Windows or on Android. And a multi-item move is a sequence of independent renames that a concurrent reader can catch halfway through.</p>
<p>Pimdir keeps the part those layouts got right, the large immutable content beside the index, and takes the part every serious PIM application already reaches for, an indexed binary store. A store is a directory with two things:</p>
<ul>
<li>pimdir.db, a SQLite database holding collections, items, per-source bindings and sync checkpoints,</li>
<li>objects/, a content-addressed blob directory holding the item bodies, one immutable file per content hash, sharded two levels deep.</li>
</ul>
<p>SQLite is a deliberate choice: its file format is byte-identical across every OS and architecture, with a stability commitment through 2050. <em>You copy a store, you do not run a server.</em></p>
<p>A few ideas do most of the work. A collection declares a <strong>media type</strong> and the store never parses the bodies, so mail, contacts and calendars are the same tables. Bodies are <strong>content-addressed</strong>, so an item filed in two collections is stored once and a copy or a move is a pointer edit rather than a byte copy. Identity is split into four distinct things (the backend handle, the cross-collection link id, the content hash, and a short public id that clients display) instead of one identifier asked to be all of them. The database is a <em>derived</em> cache, rebuildable from the blobs and a fresh sync. <strong>One process owns it</strong>, readers open it read-only, and anything else appends to an action queue the owner applies in order. And a removal is <strong>retention, not deletion</strong>: when the last source drops an item the row is kept until an explicit purge, so a remote expunge never destroys the local copy.</p>
<p>The specification is still a <em>draft</em>, it lives in the repository next to its canonical SQL schema and queries, and io-pimdir is the reference Rust implementation. Draft means it can still move, and this is the year it should stop moving.</p>
<h2>Sync, built on pimdir</h2>
<p>A store format is only half the story. The other half is keeping it in agreement with a remote.</p>
<p>That layer is <a href="https://github.com/pimalaya/io-replica">io-replica</a>, an offline-first replica engine written in the same I/O-free style. It reconciles local and remote changes with a <strong>three-way merge against a stored base</strong>, so an edit made offline survives the next sync instead of being silently overwritten. It deduplicates, so an item in several collections is fetched once. It caches partially, so a collection can be known by identifiers, by summaries or in full, and still tell &quot;deleted&quot; apart from &quot;not fetched yet&quot;. Flags merge without ever conflicting; diverging bodies are kept on both sides for a human to resolve.</p>
<p>The interesting consequence of putting this above a generic store is that <em>it stops being a mail feature</em>. The engine reconciles collections of items; what an item is, it does not care. Sync, backup, mirroring and one-off migration between two backends become <strong>the same machinery under different policies</strong>, and <a href="https://github.com/pimalaya/neverest">Neverest</a> is the CLI that exposes them.</p>
<h2>More domains</h2>
<p>The stack was built for mail first, and <strong>mail is in good shape</strong>: IMAP, SMTP, JMAP, Maildir and the provider APIs, driven by <a href="https://github.com/pimalaya/himalaya">Himalaya</a> and its TUI.</p>
<p>Contacts followed and are close behind: <a href="https://github.com/pimalaya/cardamum">Cardamum</a> speaks CardDAV, vdir, Google and Microsoft, on top of vcard-rs, which carries a version-agnostic vCard model, a byte-faithful syntax tree, and the jCard and JSContact conversions.</p>
<p><strong>Calendars are the current front.</strong> <a href="https://github.com/pimalaya/calendula">Calendula</a> is taking shape over CalDAV and local vdir, on top of ical-rs, the iCalendar twin of the vCard library, JSCalendar and three-way merge included.</p>
<p>Tasks are the plausible next one, and cheaply so: a to-do is a VTODO, which the iCalendar model already parses, and a task list is a collection of a media type the store already accepts. That is the whole argument for doing the generic work first: adding a domain should be <strong>a connector and a media type, not another silo</strong>.</p>
<h2>Higher interfaces</h2>
<p>None of the above is something a user sees. Interfaces are, and they are where the layering finally pays off.</p>
<p>The terminal is well covered: a CLI, a TUI, editor plugins. What is missing is everything else. There is a native GTK4 and libAdwaita desktop application for Linux, and Android apps for mail, contacts and calendars converging into one client. Both are being replanned onto io-replica and io-pimdir, which is exactly the intended shape: an interface should be <strong>a view over the local store</strong>, fast and useful with no network at all, with sync happening <em>behind</em> it rather than in front of it.</p>
<p>An offline-first store is the feature that makes a mobile client tolerable and a desktop client pleasant. That is why the plumbing year comes first.</p>
<h2>In short</h2>
<p><strong>One store format, one sync engine, more domains behind them, and interfaces that are finally just views.</strong> That is where the coming year points.</p>
<p>It is a direction and <em>not a plan</em>: the specification is a draft, the priorities will move as the work meets reality, and the detailed roadmap is still to be defined. What is certain is that all of it lands in the open, under free licences, as it always has.</p>
<p>Thanks to NLnet and to the NGI programs for making the slow, unglamorous, load-bearing part of this possible. Follow along here, or on <a href="https://matrix.to/#/#pimalaya:matrix.org">Matrix</a> and <a href="https://fosstodon.org/@pimalaya">Mastodon</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>The story behind Pimalaya</title>
      <link>https://blog.pimalaya.org/the-story-behind-pimalaya/</link>
      <guid isPermaLink="true">https://blog.pimalaya.org/the-story-behind-pimalaya/</guid>
      <pubDate>Mon, 03 Aug 2026 00:00:00 GMT</pubDate>
      <description>A Vim plugin that had no business managing mail, the backlash and the love it got, and the split between UI and logic that became a whole project.</description>
      <content:encoded><![CDATA[<p>Pimalaya is today a constellation of low-level libraries, CLIs, TUIs and mobile apps around personal information management. But it did not start as a project, nor as a plan. It started as a Vim plugin that had no business existing.</p>
<h2>Mails inside Vim</h2>
<p>Years ago I discovered Vim, and like many people who fall into it, I fell hard. Once your editor becomes the place where you think, you want everything in it: notes, tasks, code, and, in my case, mails.</p>
<p>So I wrote <a href="https://github.com/soywod/iris.vim">iris.vim</a>, a plugin to manage mails inside Vim. Reading, replying, archiving, without leaving the editor.</p>
<p>The reception was… polarized. Some people hated me for torturing Vim: it is a text editor, not a mail client, and the plugin ecosystem was never meant to carry a mail workflow. Others loved the concept: their editor was already their home, and mail was the one thing still dragging them elsewhere.</p>
<p>Both sides were right, and that tension turned out to be the founding insight of everything that came after.</p>
<h2>Splitting the UI from the logic</h2>
<p>The critics had a point: Vim is a terrible place to <em>implement</em> a mail client. Fetching, parsing, encoding, talking to servers: none of that belongs in a plugin. But the lovers had a point too: Vim is a wonderful place to <em>display</em> one.</p>
<p>This is where I started to split the UI from the logic. The domain (everything mail knows how to do) should live outside the editor, in a proper program. The editor should only be a frontend: buffers in, keystrokes out.</p>
<p>Once the logic is its own program, the frontend becomes swappable. Vim today, something else tomorrow.</p>
<h2>A CLI, in Rust</h2>
<p>The shape of that program came naturally: a command-line interface. I had wanted to learn Rust for a while, and a mail CLI fit perfectly: innovative (the terminal mail world was full of TUIs like mutt, but a plain, scriptable CLI was rare), the right size for learning a new language, and exactly the backend a Vim frontend needed. The plugin would just shell out and render the output.</p>
<p>That CLI became <a href="https://github.com/pimalaya/himalaya">Himalaya</a>.</p>
<h2>Then it grew</h2>
<p>The CLI was supposed to be the end of the story. It was actually the beginning, and the same splitting instinct kept applying itself one level down:</p>
<ul>
<li>The email logic was extracted from the CLI into a dedicated library, so other tools could reuse it.</li>
<li>The protocol logic was extracted from the email library into low-level libraries (IMAP, SMTP, and friends), so the email layer itself became swappable.</li>
<li>A TUI joined the CLI, proving the point of the whole architecture: same logic, another frontend.</li>
<li>Then other PIM domains knocked on the door: if it works for mails, why not contacts? Why not calendars?</li>
</ul>
<p>At some point this stopped being &quot;the Himalaya ecosystem&quot; and became its own project: Pimalaya.</p>
<h2>Here we are</h2>
<p>Today Pimalaya is full of low-level libraries, and fully mail-capable: Himalaya CLI, a TUI, mobile apps on the way. Contacts are coming next, then calendars.</p>
<p>The plugin that tortured Vim is long gone, but its lesson is load-bearing in everything we build: the domain logic lives in reusable layers, and the UI (editor, terminal, phone) is just a view on it.</p>
<p>Not bad for a plugin some people hated.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Welcome to the Pimalaya blog</title>
      <link>https://blog.pimalaya.org/welcome/</link>
      <guid isPermaLink="true">https://blog.pimalaya.org/welcome/</guid>
      <pubDate>Sun, 02 Aug 2026 00:00:00 GMT</pubDate>
      <description>Newcomers, take a moment to read this post: you will understand why this blog exists and what it covers.</description>
      <content:encoded><![CDATA[<h2>What is Pimalaya</h2>
<p>Pimalaya is an ambitious project that aims to <strong>improve the open-source tooling around personal information management</strong> (also known as PIM): emails, contacts, calendars (events, tasks, journals, alarms), timers, files, and whatever else turns out to belong there.</p>
<p>It comes in two halves. The <strong>libraries</strong> are low-level Rust crates for protocols and storage, reusable by anyone. The <strong>applications</strong> are what we build on top of them: CLIs, TUIs, editor plugins, mobile apps and native desktop GUIs.</p>
<p>One rule binds them together: the libraries are <em>I/O-free</em>. They carry the whole protocol logic as state machines and perform no read, no write and no network call of their own, so the application stays in charge of blocking or async, of which runtime and of which TLS. That single constraint is why the same IMAP code can run in a terminal, in a daemon, and inside an Android app over a Kotlin-owned socket.</p>
<p>Today mail is the mature domain (a CLI, a TUI, Vim and Emacs plugins), contacts and calendars are catching up, mobile and Linux desktop applications are underway, and the offline-first sync stack is the current frontier.</p>
<h2>Why a blog</h2>
<p>What Pimalaya has used for a while:</p>
<ul>
<li><strong><a href="https://pimalaya.org">Website</a></strong>: the front door. What Pimalaya is, and where everything else lives.</li>
<li><strong><a href="https://github.com/pimalaya">GitHub</a></strong>: the code, the bug reports, and the design discussions that lead to decisions.</li>
<li><strong><a href="https://matrix.to/#/#pimalaya:matrix.org">Matrix</a></strong>: real-time chat and support. Nothing said there is meant to last.</li>
<li><strong><a href="https://fosstodon.org/@pimalaya">Mastodon</a></strong>: the megaphone. Short announcements pointing at something durable.</li>
</ul>
<p>What it never had is <em>a durable place</em>, where the project&#39;s direction gets written down in full sentences: why a release took the shape it did, what is coming next, and what got retired along the way. This blog is that place. The <a href="/feed.xml">RSS feed</a> and the <a href="https://buttondown.com/pimalaya">newsletter</a> are just two read-only views on it: subscribe to whichever fits your reading habits.</p>
<h2>What to expect</h2>
<p>Three kinds of posts, all in the same half-technical register.</p>
<ul>
<li><strong>Journal and news</strong>: the running account of the project, on both the PIM domain side and the technical side (what is being built, reworked, or retired, and why). This is the logbook behind the short Mastodon announcements.</li>
<li><strong>Architecture and design</strong>: the reasoning behind how Pimalaya is built. These posts lean more technical than domain: the choices, the trade-offs, the alternatives that were <em>rejected</em>, and the patterns shared across the libraries and the applications.</li>
<li><strong>Releases, in depth</strong>: when something ships, the release post goes further than a changelog. What changed for users, what changed under the hood, and the decisions behind both.</li>
</ul>
<p>Expect the occasional detour into a <strong>dead end we walked into and walked back out of</strong>. Those are usually the most instructive ones, and they never fit in a changelog.</p>
<p>See you in the feed.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
