How OpenCalendar works, and how to use it.
Everything here describes the app as it is today. Where something is built but not yet switched on, or still being built, it says so.
- Getting started
- Connect, use and disconnect a calendar
- Make it the default app for calendar files
- How the scheduling link works
- Meeting links
- Shared calendars and polls
- What the relay can and cannot see
- For agents: the CLI and MCP server
- Running your own helper and relay
- Your key and backups
- The account, which is optional
- Known limits
- Removing OpenCalendar
Getting started
- Open the app. No sign-up is needed. The first time it runs, the app makes a key in your browser; it is how people who book you know a link is yours.
- Add a calendar: open a calendar file, follow a calendar address, or press + beside Calendars to start an empty one.
- Open Scheduling links, press New link, fill in what guests should see and when you can meet, and press Save and publish.
- Press Copy link and send it to someone.
Your calendars, links and key are kept in this browser only. Read Your key and backups before you rely on it.
Connect, use and disconnect a calendar
Every calendar you tick in the sidebar is shown in the grid and counts as busy time for your scheduling links.
Calendar files Available
- Connect: press the file button beside Calendars, or drag a file onto the app. It reads
.ics,.vcsand.ifbfiles. - Use: the events become a calendar in your browser that you can add to and change. An invitation in a file can be answered; the app gives you a reply file to send back. Any calendar can be exported as an
.icsfile, with its attachments inside. - Disconnect: delete the calendar in the app. The file on your computer is not touched.
Followed calendars Available
- Connect: add a
webcal:orhttps:calendar address. Google Calendar and Outlook can usually give you a private address for a calendar in their own settings. - Use: the calendar is read-only here and is refreshed at most once an hour. If the site that hosts it does not allow web pages to read it, the app asks the helper to fetch it.
- Disconnect: delete the calendar in the app. Nothing is kept anywhere else.
Google Calendar Built · awaiting Google’s approval
Not available yet. The connection is built and is waiting for Google’s review of the app; until then Settings shows no Connect button for Google. These are the steps once it is switched on.
- Connect: Settings, Accounts, Connect Google. Google shows its own consent screen naming OpenCalendar and two permissions: seeing your list of calendars, and viewing and editing events. Tick both. Then choose which of the account’s calendars to show.
- Use: the account’s events appear in the grid and count as busy for your links. They are read-only in OpenCalendar. When a booking through one of your links is confirmed, the app writes it to the Google calendar you chose for bookings, with your guest as an attendee and a Google Meet link, and Google emails the guest its invitation.
- Disconnect: Settings, Accounts, Disconnect. This forgets the sign-in in this browser and takes the account’s calendars out of it; the events stay in your Google account. To withdraw the permission at Google as well, remove OpenCalendar at myaccount.google.com/connections.
What is read, where it is kept and who can see it is in the privacy policy, under Google user data.
Microsoft Outlook and Microsoft 365 Built · awaiting registration
Not available yet. The connection is built and is waiting for the app’s registration with Microsoft; until then Settings shows no Connect button for Microsoft. These are the steps once it is switched on.
- Connect: Settings, Accounts, Connect Microsoft. Microsoft asks you to approve one permission, reading and writing your calendars. On a work or school account you may see “needs admin approval”; the app then gives you a link to send to your IT administrator, and a page written for them.
- Use: as with Google. A confirmed booking is written to the calendar you chose, with a Teams link on a work or school account. A personal Outlook.com account cannot create Teams links.
- Disconnect: Settings, Accounts, Disconnect. To withdraw the permission at Microsoft, remove OpenCalendar from the apps with access to your account, or ask your administrator to.
iCloud and other CalDAV servers Built · not available yet
Built, and not available yet. The connection has been proven against a CalDAV server of another make, not against iCloud or Fastmail themselves; and in a browser it needs the helper, which is not running yet. Until it is available, an iCloud calendar can be followed through its public calendar address, or opened from an exported file.
Make it the default app for calendar files
An installed copy of the web app can open calendar files from your computer. This works in Chrome and Edge on a computer. A desktop app that does this without a browser is being built and is not available yet.
- Install it. Open the app and choose Install from the browser’s address bar or menu.
- Open a file with it. Right-click an
.ics,.vcsor.ifbfile, choose Open with, and pick OpenCalendar. The first time, the browser asks whether to allow it. - Make it the default. On a Mac: select the file, choose Get Info, set Open with to OpenCalendar and press Change All. On Windows: right-click the file, choose Open with, Choose another app, pick OpenCalendar and choose Always.
- Calendar links. In Settings, under Calendar links, press Open calendar links here so that
webcal:links, the kind a “subscribe to calendar” button uses, open in OpenCalendar.
How the scheduling link works
A scheduling link looks like this:
https://opencalendar.me/app/#/b/npub1…/intro?k=…
Everything after the # stays in the browser: your public key, the link’s name and the link’s own key. A web server never receives it.
- You publish. Your browser encrypts the page (title, lengths, hours, questions, meeting link) and the times you are busy inside the booking window, using the link’s key, and leaves both on the relay. Busy times are start and end only, rounded to the slot size.
- The guest opens the link. Their browser fetches those records, opens them with the key in the link, and works out the free times itself: your hours, minus your busy times, minus slots already claimed. It shows each time in the guest’s zone and yours, and says when your calendar was last read.
- The guest books. Their browser leaves two records: a claim on the slot, and a sealed request that only you can open, with their name, email address and answers.
- The claim stops double booking. Every guest’s browser reads the claims and treats a claimed slot as taken. The earliest claim on a slot wins. This works while all of your devices are off.
- You answer. When your app is next open it checks the slot against your calendars, adds the meeting, and sends a sealed reply: confirmed, declined, or other times. The guest’s private status link shows the answer, and lets them move or cancel.
When a booking counts as confirmed
You choose on each link:
- Automatically. The first valid claim on a free slot is the booking.
- On request. A claim holds the slot and you approve or decline.
- Automatically while fresh. Automatic while your busy times are newer than a limit you set, a request once they are older.
Group links
A group link lists several hosts by public key, and a rule: everyone must be free, or any one host may take the meeting (round-robin). Each host publishes their own busy times, signed with their own key. The guest’s browser combines them. No host sees another’s calendar, and the request goes to each host. To be added to a group, copy your public key from Settings and give it to whoever makes the link.
A host who cannot connect their work calendar can still take part, with busy times from a followed calendar address or a file.
Meeting links
- A standing room link. Paste your Zoom, Google Meet, Microsoft Teams or Tencent Meeting room link into the scheduling link once. Every booking carries it. This needs no approval from any of them and no account connected to OpenCalendar.
- A link made per booking. Built for Google Meet and Microsoft Teams, and available once the Google and Microsoft connections are switched on. Not available yet.
- Zoom and Tencent Meeting are pasted links only. OpenCalendar has no Zoom app and does not connect to a Zoom account.
Shared calendars and polls
Sharing a calendar. Open the calendar’s Share dialog, paste a person’s public key, give them a name, and choose what they may do: see only when it is busy, see events, or see and change events. Events are encrypted on your device before they are sent. Removing someone issues new keys, so they cannot read what is written afterwards; what they already have, they keep. Attachments are not shared: other members see a file’s name and size only.
A meeting poll. In Scheduling links, press New poll, propose a few times and send the link. Each person answers yes, maybe or no in their own time zone. A vote is signed by a key the voter’s browser makes, so nobody holding the link can change someone else’s answer. You pick the time and the meeting is added to your calendar.
What the relay can and cannot see
The relay is a server that stores and forwards signed, encrypted records. The app uses wss://relay.opensync.network/ unless you set another in Settings. It is the only server that holds anything of yours, and it holds it sealed.
| The relay can see | The relay cannot see |
|---|---|
| That encrypted records exist, how large they are, and when they arrived | Your events, their titles, places or attendees |
| The public key that signed a scheduling page and its busy times — the host’s | What the page says, or when the host is busy |
| That a one-day key left a claim, with an opaque tag | Which link or which slot the claim is for |
| How many sealed messages are addressed to a public key | Who sent them, what time they are about, or what they say |
| The network address of each connection | The link’s key: it is never sent to any server |
Three things to know, because they are not obvious:
- Reading needs no sign-in. Anyone can fetch any stored record. They are all sealed, so the content is safe, but anyone can count the messages left for a given public key.
- Whoever holds a link can read that link. The page and your busy times are open to every person you send the link to, and to anyone they forward it to. Busy times never include titles.
- There is no delete. Records leave the relay by expiring: a claim a day after its slot, busy times a day after their week, booking messages after 30 days. A scheduling page has no expiry and stays, sealed, until it is replaced.
For agents: the CLI and MCP server
opencalendar is the same scheduling core as the web app, built as a local program, so the times it offers are the times the page offers. It runs on your own machine and talks to the relay directly. There is no hosted endpoint.
It builds from the source with Cargo. The public repository is not open yet, so there is nothing to download today; these are the commands once it is.
cargo build --release -p cal-cli
opencalendar mcp # an MCP server on stdin and stdout
opencalendar tools # list the tools
opencalendar find_times '{"link":"https://opencalendar.me/app/#/b/npub1…/intro?k=…","tz":"Europe/London"}'
To give it to an MCP client, register the command:
{ "mcpServers": { "opencalendar": { "command": "opencalendar", "args": ["mcp"] } } }
| Tool | What it does |
|---|---|
link_info | Reads a scheduling link: who it is with, how long, where, in which time zone, and whether a booking made now is confirmed at once or is a request |
find_times | The open times on a link. For a group link, the times that work for the group |
propose_booking | Books one open time for a named person. Returns whether it is confirmed or a request, and a private status link |
booking_status | What became of a booking: waiting, confirmed, declined, cancelled, or a counter-proposal |
reschedule_booking | Moves a booking to another open time on the same link |
cancel_booking | Cancels a booking and tells the host |
read_calendar_file | The events in .ics files on this machine, with repeating events expanded |
free_time | When the owner of some .ics files is free for a meeting of a given length |
The rules it keeps, so that an agent cannot quietly get a time wrong:
- Every time carries its UTC offset. A time without one is refused.
- Anything that publishes takes
dry_run, to see the outcome without booking. - Booking takes an
idempotency_key, so a retry does not book twice. - Text written by the other party is marked as data, not as instructions.
- It holds no key of yours. It books with a key made for that booking, exactly as a guest’s browser does.
What it does not do today: read or change the calendar inside your OpenCalendar app, or act as you on a shared calendar. It books on links, as a guest would, and reads calendar files.
Running your own helper and relay
The helper is a small program that does the two things a web page cannot: fetch a calendar address from a site that does not allow web pages to read it, and add the secret Google requires to complete or renew a sign-in. It has no database, writes no file, and logs no address, token or body. It answers only the one app origin it was started for.
GET /healthz
GET /fetch?url=https://… a calendar file, passed through
POST /google/token a sign-in code or a refresh token, passed to Google
To run your own beside your own copy of the app:
HELPER_BIND=127.0.0.1:5208 \
HELPER_ALLOW_ORIGIN=https://calendar.your-domain.example \
GOOGLE_CLIENT_ID=… GOOGLE_CLIENT_SECRET=… \
cargo run --release --manifest-path crates/cal-helper/Cargo.toml
Then tell your copy of the app where it is, in the app’s config.json. No rebuild is needed:
{ "googleClientId": "…", "microsoftClientId": "…", "helperUrl": "https://helper.your-domain.example" }
HELPER_ALLOW_ORIGINis your app’s origin with no trailing slash. Requests from anywhere else are refused.- The Google values come from a “Web application” client that you register with Google yourself. Without them the helper still fetches calendars and refuses Google sign-ins.
- It fetches only
httpsaddresses on the public internet, follows no redirects on its own, stops at five megabytes, and passes on only calendar files. - Put it behind TLS. If a web server sits in front of it, turn off that server’s logging of query strings: the address of a followed calendar travels in one.
Your own relay. Set its address in Settings, under Relay. The app needs a relay that will store application data (kind 30078) and gift wraps (kind 1059) from keys it has not seen before. The relay the app uses by default is open source, at github.com/open-sync/opensync. A link published to another relay carries that relay’s address, so your guests’ browsers are sent to yours.
Your key and backups
- Your key is made in your browser and is never sent anywhere. The public half (
npub1…) is what you give others so they can add you to a group link or share a calendar with you. - The secret half is stored in the browser, unencrypted, until you export it. In Settings, under Your key, type a password and press Save an encrypted backup. Keep the backup and the password apart.
- To move to another browser, use Use a key I already have there. Links made with the old key keep receiving bookings only where that key is.
- Calendars are not in the key backup. Export each calendar as a file.
The account, which is optional
The round button at the top right of the app opens the account page. The account is one sign-in shared by our apps, with a balance of credits that the apps with paid features spend. OpenCalendar needs none of it. Nothing in the app is behind the account, nothing in it costs credits, and a booking page, a status page or a poll never shows it.
- Signing in. The page offers the ways our account server accepts: today Google, OpenWallet ID, a crypto wallet or a Nostr key. Signing in sends the window to the provider you choose and back to the account page.
- Signed in, the page shows the account and its balance, a way to buy credits, and where credits went. Sign out from the same page. Delete account… there removes the account and everything our account server holds with it; credits left in it are lost.
- It is not your calendar. Your calendars stay in this browser whether you sign in or not. The app sends the account server nothing about them, or about your links and bookings.
- It is not your key. People book you with the key under Settings, Your key, and signing in to the account does not change it. If you use the OpenWallet browser extension, Settings also offers “Sign in with OpenWallet”: that hands your key to the extension to keep. On the account page the same words sign you in to the account with OpenWallet ID. Neither one does the other.
- It is not a connected calendar. Settings, Accounts is where a Google or Microsoft calendar is connected. Signing in to the account with Google asks Google only for your name and email address, and connects no calendar.
What the account server holds, and how to remove it, is in the privacy policy.
Known limits
- Busy times are as fresh as your last session. Nothing runs while none of your devices has the app open. The page shows the age of your busy times, and a link can turn bookings into requests when they are too old.
- No email, reminders or push from us. Sending them needs a server. New bookings appear in the app while it is open. Once a connected Google or Microsoft calendar holds the event, that provider sends its own invitation and reminders.
- People who hold the same link are trusted with each other. One holder of a link can overwrite another’s claim on a slot. You still receive both sealed requests and decide.
- A link can be flooded with claims. The relay limits how fast one key and one address may write; changing the link’s key shuts the old link.
- The key lives in the browser’s storage, unencrypted, until you export it under a password. Clearing the site’s data loses it.
- Attachments do not travel with a shared calendar. Other members see the name and size, and “Not on this device”.
- Time-zone rules are as new as the app’s last update. The time-zone database is built in. A change announced at short notice is right once the app has been updated.
- Events from a connected account are read-only here, apart from the bookings the app writes itself.
Removing OpenCalendar
- Export any calendars you want to keep.
- Disconnect connected accounts in Settings, Accounts, and remove the app’s access at Google or Microsoft if you connected one.
- If you signed in to the optional account and want it gone too, open the account page and press Delete account…. Signing out alone leaves the account where it is.
- In Settings, press Delete everything here. This removes every calendar, link, booking and the key from the browser. It cannot be undone.
- If you installed the app, uninstall it from the browser’s app menu.
Once the key is gone, a booking made through a link you gave out reaches nobody, so tell the people who have one. What remains on the relay is sealed and expires as described under the relay; the details are in the privacy policy.