Hosting iCal via GitHub Gists

by · ·2 min read ·344 words

I’ve been using Claude to help organize my swim/bike/run schedule. I can give it a goal race, set some parameters, let it know what my current schedule looks like, and it’ll spit out a basic training plan as a static website that I can host on my tailnet and also an iCal file that I can subscribe to. I want Claude to be able to update the iCal file and I want it hosted somewhere that I don’t need to think too much about. It turns out that GitHub gists are handy for this. I can have Claude create a secret gist which I then subscribe to on my phone. If I alter the plan, Claude updates it and the changes sync to my phone when it next polls the feed. The caveat is that the gist itself is secret but not private. I accept that tradeoff for this particular use case. It’s one less thing for me to have to think about.

featured

"Improved LEGO Calendar Front" by Bill Ward's Brickpile is licensed under CC BY 2.0.

The feed URL ends up looking like: https://gist.githubusercontent.com/<user>/<gist-id>/raw/<file>.ics. You get TLS for free, which is good because your calendar likely requires it.

$ curl -I https://gist.githubusercontent.com/<user>/<gist-id>/raw/<file>.ics
HTTP/2 200
cache-control: max-age=300
content-type: text/plain; charset=utf-8
etag: "<hash>"
x-content-type-options: nosniff
date: Tue, 06 Oct 2026 15:40:27 GMT
x-cache: HIT
expires: Tue, 06 Oct 2026 15:45:27 GMT
source-age: 124

The HTTP header that matters is content-type: text/plain; charset=utf-8. While the text/plain content type is something that iCal seems to have no issue with, it probably wants text/calendar. In practice for me this has worked out fine, but your mileage may vary.

We can also see that the gist is cached for up to 5 minutes, so updates will not be immediate in the calendar sync. Not really an issue for me as my training schedule rarely changes. Also, be sure to use the URL format as shown above so that you always get the updated gist rather than one that is pinned to a SHA.

Related posts: