Skip to main content

Command Palette

Search for a command to run...

Calendar or it didn't happen

Updated
10 min readView as Markdown
Calendar or it didn't happen
J

👋 Hey! I'm Jakub Beneš, a Software Engineer based in Prague.

I'm passionate about scaling engineering, organizational design, and leadership. I'm a huge fan of web technologies and modern approaches within this field. While I'm a strong contributor on the frontend side, lately, I've been focusing more on the entire stack and infrastructure because there's often low-hanging fruit that can deliver a massive impact – and I enjoy seizing such opportunities. I'm not sure if I'll ever start liking YAML, though. 🤓

It's 7pm in Prague. I'm on a call with New York, where it's 1 PM and nobody in the room is thinking about bath time. In the next room, my partner is doing the evening shift on her own — the one I had promised to take.

Nobody did anything wrong. The meeting went into an hour my work calendar showed as free, because the only place that hour was spoken for was a calendar my colleagues can't see.

Sharing a calendar with your partner is an obvious choice. Until you have two kids and six hours of time zone between you and the people you work with — and then it turns out the calendar isn't the hard part. The hard part is that I have two of them, and they have never heard of each other.

Our Flow

My partner and I share a Google Calendar. Both subscribed, nothing fancy, the same setup half the families I know have.

What we added on top is a convention. If one of us is claiming a slot for themselves, the event gets a prefix: J: for me, P: for her. Two characters and a colon.

Two real entries:

  • P: dinner with the girls

  • Swimming pool with E.

(Ours are in Czech, but you get the idea. 😀)

The first is my partner taking an evening for herself. The second is a Saturday with our daughter — a family thing, nobody claiming anything, an event that changes nobody's plans.

Only the first one costs me a working hour, and this is the bit I like: it costs me one even though it's her event. She's out, so the kids are mine. A J: costs me the same hour for the ordinary reason — it's my own commitment. Two letters, two completely different stories, one identical consequence: an hour my work calendar doesn't get to have.

Everything unprefixed stays put, and most of the calendar is unprefixed. That's rather the point. The convention marks the exceptions, not the routine.

Once you see it that way, a shared family calendar stops being a record of where two people are. It becomes a ledger of claims on time, and the prefix says who filed one.

Honestly? I really like it — though I'm quite calendar-native, so whatever floats your boat.

But I immediately discovered that the convention was never the problem.

The problem was that I was the integration layer. Every prefixed event had to be copied by hand into my work calendar, or a colleague would book straight over it. Twice a day, from memory, on a phone, usually while walking somewhere.

I was a sync engine with a genuinely terrible uptime record.

"Just share the calendars"

This is the point where somebody tells me Google already does this. And it does — it just does the wrong thing.

Let's pretend for a moment that I could publish my work calendar as an .ics feed. (I can't. Most enterprise setups I've come across won't let you, and mine is no exception.) My partner could subscribe to it, and we'd be left choosing between two bad options: layer it over our shared calendar and read a wall of meetings that mean nothing to her, or keep it in a separate view she has to remember to check before planning anything. One is noise. The other is the thing you forget precisely when it matters.

Going the other way is harder still. I don't want my colleagues subscribed to anything of mine. I need the blockers to live in my work calendar — real events, in the calendar their scheduling assistant actually reads when it goes looking for a free hour. A subscribed calendar sits alongside that one. It doesn't defend it.

Nobody wants a merge. Everybody wants a filter.

The filter I actually want is narrow: copy the prefixed events, drop everything else, and strip the copies down to the one fact worth knowing. The pool trips, the birthday parties, the ordinary shared weekend — New York has no use for any of it, and it stays exactly where it is.

There's no setting for that in the calendar apps I've used, because it isn't a setting — it's a rule, and rules are code.

So I built the pipe

CalendarPipe connects Google Calendar, Outlook and Apple Calendar through pipes: rules that filter, transform and route events between them. You write a small function, it runs on every event, and it decides what — if anything — comes out the other side.

My family rule is the actual one running on my account right now:

function gate(event: GateEvent): GateResult {
  if (
    (event.title.toLowerCase().includes('j:') ||
      event.title.toLowerCase().includes('p:')) &&
    event.isWeekday === true &&
    event.isAllDay === false
  ) {
    return {
      pass: true,
      transform: {
        title: 'Personal Commitment',
        visibility: 'public',
        showAs: 'busy',
        location: '',
        preBufferMinutes: !!event.location ? 30 : 0,
        postBufferMinutes: !!event.location ? 30 : 0,
      },
    };
  }
  return { pass: false };
}

It isn't much, but every line is load-bearing:

  • Either prefix, weekday, not all-day. J: and P: both cost me the hour, for the two different reasons above. All-day entries are noise — birthdays and public holidays don't need to defend a working hour.

  • Personal Commitment, public, busy. My colleagues get the hour and nothing else. Nobody in New York needs to know whether it's a parent-teacher meeting or a dentist.

  • location: ''. The field I'm most careful about. Clearing it means my kids' school never turns up in a corporate calendar.

  • The buffers. If the original event has a location, I take 30 minutes either side of it, because a physical event means travel, and Prague traffic has never once cared about my standup.

And then my own work calendar got in the way. Naturally, the first thing I wanted was to write straight into Outlook — but our policy prohibits connecting unapproved tools that ask for that kind of scope, which meant my own product couldn't solve my own problem. That's a humbling afternoon, I can tell you.

So we built a second way in. Instead of writing events into the target calendar through an API, CalendarPipe can send them as ordinary email invitations — the same .ics meeting invites your colleagues fire at you all day long. An invite arrives at my work address, I hit Accept, and the event lands on the calendar I was never allowed to connect. IT doesn't have to permit anything new, because inbound invitations are how every meeting on earth already works.

As far as I know, no other calendar sync tool does this. Feel free to prove me wrong in the comments — I looked before I built it, and I'd have been delighted to find it already existed.

The whole thing started as a joke, by the way. I was telling my friend Tomáš that piping calendar events through a JavaScript function surely couldn't be that hard, and instead of talking me out of it he said he'd use it — his family runs the same kind of shared calendar. So I built the prototype that weekend and pulled him in once it worked.

The repo is unsentimental about the timeline. First commit on a Friday at 21:18, which is roughly when the kids go down. By 23:22 that night OAuth worked. By Saturday afternoon there were gate functions that could actually transform an event. Tomáš's first commit lands the following Wednesday. It also gave us an excuse to meet every two weeks over a beer and plan the next batch of work in person. Win-win. 🍻

I did write a post about outcomes over outputs some time ago, and I'm aware of how this looks. The outcome I wanted was "stop double-booking the bath time I promised to take." And somehow, along the way, the output became a calendar sync product with paying customers. I'd like to claim those are the same size. They are not.

But I use it every single day, which is more than I can say for most things I've built.

I was wrong about who this was for

I should switch to "we" here, because I'm not doing this alone. I build CalendarPipe with my friend Tomáš (aka Zuse), and somewhere along the way it also became the best playground either of us has for agentic development — new tools, new workflows, new ways of handing the boring parts to an agent and seeing what survives contact with a real product. That's a post of its own, and I'll write it (one day, haha).

Anyway. We built it for people like us. Programmable rules, a proper code editor, a sandbox to run your functions in — the pitch was basically "calendar sync for nerds," and I meant it as a compliment.

The customers who actually showed up are consultants.

Which makes sense the moment you stop assuming everyone shares your problem. Someone running four client engagements has four calendars they can't merge, for reasons that are contractual rather than domestic. They need one honest view of when they're free, without leaking client A's schedule into client B's invite. That's the same ledger of claims again — it's just that for them it's the job rather than the evening, and they'll happily pay to stop doing it by hand. Based on that feedback we built a visual builder, and even AI-assisted pipe creation.

The launch

We took CalendarPipe to Product Hunt and ended up eighth product of the month. For context, that same month had OpenAI, Anthropic and Canva shipping, so I've made my peace with the seven places above me. You never plan a launch right — but this one I did: it landed on a Vercel day, and by luck the whole thing is fully serverless on Next.js.

It went well enough that Vercel handed us a year of their services as a prize. Hosting: covered ✅. The service barely pays for itself, so a free year buys us real runway. I have a full-time job, and CalendarPipe happens after the kids are asleep. Somewhere in there I stopped switching the PlayStation on. I'm told that's a phase.

I won't pretend a launch changes much. The traffic spikes and then it doesn't. What it does change is the question you're carrying around: it turns "is this only my problem?" into "no, apparently not." That's worth more than the spike.

Anyway

If you've got a version of this problem — a calendar that needs to tell another one something, but not everything — I'd like to hear how you're solving it today. Especially if the answer is "by hand, twice a day, badly." That was my answer for years.

Thanks to my partner, who invented half of this system and tolerated the months when I was building software instead of doing the dishes. And to Tomáš, who builds the other half of the product with me.

See you around, my friends.

P.S. More than 300 events have gone through my own pipe since I turned it on.

More from this blog

W

Welcome, I'm Jakub!

9 posts

👋 Hey, I'm Jakub – Software Engineer based in Prague. I went full circle from IC to EM and now I'm back. Don't hesitate to drop me a DM and ask for anything!