--- title: The feature I said no to (and the one I found instead) description: >- A user asked Calendula to sync itself to a plain .ics file. Talking it through in the open turned a "no" into a better, smaller feature — and clarified what the app is actually for. pubDate: 2026-07-10 tags: [open-source, calendula, open-standards] draft: true --- One of the more useful things that has happened to Calendula wasn't a feature I added. It was one I turned down — in public, in a comment thread, with the person who asked for it ([#7]). The request: let Calendula save its calendar state to a file. Prompt for an `.ics` on startup, write back on every change, so events are never "trapped" in the app. Reasonable on its face. My answer was no — but the interesting part is how we got from there to something I *did* ship. ## Why it was a no Calendula doesn't own your data. It's a client for Android's system calendar provider, and the syncing is left to whatever CalDAV adapter you've already set up — DAVx5, SmoothSync, whatever moves your events today. A "write to an .ics on every change" feature quietly reintroduces the exact thing the app exists to avoid: it starts handling sync itself. And live file sync is genuinely hard, for a reason that has nothing to do with effort. The moment two sides can edit the same event — a local change and a synced-in change landing on the same slot — *something* has to decide which wins. CalDAV has machinery for that. The `.ics` format doesn't; it was designed for backups and for handing events from one place to another, not for being written to continuously. Build the feature and you inherit a merge engine you now have to get right forever. As I put it in the thread: as a developer you want a database to talk to, not to hand-roll storage and eat all the hiccups that come with it. ## Why saying no in the open mattered I could have just closed the issue with "out of scope." Instead we talked it through, and the request opened up into something more specific than the first sentence. What the reporter was after wasn't live bidirectional sync — it was a guarantee that their events could exist as a file that isn't hostage to one app. Their words, as we got there: "just a way to automatically write and read into a file without it ever being trapped in the application." That's a completely different, and much smaller, feature. Not a sync engine — a **periodical auto-export**: set an interval, and at that interval your calendar is written out to an `.ics`. No merge problem, because it's one direction. No philosophy problem, because export *is* what the format is for. That became [#8], and it satisfied the actual need — "That satisfies me!" was how the thread closed. I also pointed them at [ICSx5] and mentioned a separate app, the DAVx5 pattern, would be the honest home for true file sync — because a real solution to their original idea deserves to exist, just not bolted into a calendar client. ## What the thread was really for The trade I keep making is that [open standards are a boundary, not a checkbox](/blog/open-standards): the `.ics` request sat just outside that boundary, and holding the line kept the app simple enough to stay trustworthy. But the lesson wasn't "learn to say no." It was that a good "no" is a conversation. The user leaves with something that works, I leave with a sharper sense of what the app is *for*, and the thread stays public so the next person can read the whole reasoning instead of a closed issue with one terse label. You don't get that from a roadmap. You get it from taking the request seriously enough to argue with it. [#7]: https://codeberg.org/jlmakiola/calendula/issues/7 [#8]: https://codeberg.org/jlmakiola/calendula/issues/8 [ICSx5]: https://icsx5.bitfire.at/