SkillAgentSearch skills...

Keeper.sh

Open-source calendar sync tool & universal calendar MCP server. Aggregate, sync and control calendars on Google, Outlook, Office 365, iCloud, CalDAV or ICS.

Install / Use

/learn @ridafkih/Keeper.sh

README

About

Keeper is a simple & open-source calendar syncing tool. It allows you to pull events from remotely hosted iCal or ICS links, and push them to one or many calendars so the time slots can align across them all.

Features

  • Aggregating calendar events from remote sources
  • Event content agnostic syncing engine
  • Push aggregate events to one or more calendars
  • MCP (Model Context Protocol) server for AI agent calendar access
  • Open source under AGPL-3.0
  • Easy to self-host
  • Easy-to-purge remote events

Bug Reports & Feature Requests

If you encounter a bug or have an idea for a feature, you may open an issue on GitHub and it will be triaged and addressed as soon as possible.

Contributing

High-value and high-quality contributions are appreciated. Before working on large features you intend to see merged, please open an issue first to discuss beforehand.

Local Development

The dev environment runs behind HTTPS at https://keeper.localhost using a Caddy reverse proxy with automatic TLS. The .localhost TLD resolves to 127.0.0.1 automatically per RFC 6761 — no /etc/hosts entry is needed.

Prerequisites

Getting Started

bun install

Generate and Trust a Root CA

The dev environment runs behind HTTPS via Caddy. You need to generate a local root certificate authority and trust it so your browser accepts the certificate.

mkdir -p .pki
openssl req -x509 -new -nodes \
  -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
  -keyout .pki/root.key -out .pki/root.crt \
  -days 3650 -subj "/CN=Keeper.sh CA"

Then trust it on your platform:

macOS

sudo security add-trusted-cert -d -r trustRoot \
  -k /Library/Keychains/System.keychain .pki/root.crt

Linux

sudo cp .pki/root.crt /usr/local/share/ca-certificates/keeper-dev-root.crt
sudo update-ca-certificates

Start the Dev Environment

bun dev

This starts PostgreSQL, Redis, and a Caddy reverse proxy via Docker Compose, along with the API, web, MCP, and cron services locally. Once running, open https://keeper.localhost.

Architecture

| Service | Local Port | Accessed Via | | -------- | ---------- | ------------------------------------ | | Caddy | 443 | https://keeper.localhost | | Web | 5173 | Proxied by Caddy | | API | 3000 | Proxied by Web at /api | | MCP | 3001 | Proxied by Web at /mcp | | Postgres | 5432 | postgresql://postgres:postgres@localhost:5432/postgres | | Redis | 6379 | redis://localhost:6379 |

Qs

Why does this exist?

Because I needed it. Ever since starting Sedna—the AI governance platform—I've had to work across three calendars. One for my business, one for work, and one for personal.

Meetings have landed on top of one-another a frustratingly high number of times.

Why not use this other service?

I've probably tried it. It was probably too finicky, ended up making me waste hours of my time having to delete stale events it didn't seem to want to track anymore, or just didn't sync reliably.

How does the syncing engine work?

  • If we have a local event but no corresponding "source → destination" mapping for an event, we push the event to the destination calendar.
  • If we have a mapping for an event, but the source ID is not present on the source any longer, we delete the event from the destination.
  • Any events with markers of having been created by Keeper, but with no corresponding local tracking, we remove it. This is only done for backwards compatibility.

Events are flagged as having been created by Keeper either using a @keeper.sh suffix on the remote UID, or in the case of a platform like Outlook that doesn't support custom UIDs, we just put it in a "keeper.sh" category.

Considerations

  1. Keeper tracks timeslots, not event details, summaries, descriptions, etc., for now. If you need that I would recommend OneCal.
  2. Keeper only sources from remote and publicly available iCal/ICS URLs at the moment, so that means that if your security policy does not permit these, another solution may suit you better.
  3. The MCP server provides read-only access to calendar data. AI agents can list calendars and query events but cannot create, modify, or delete them.

Cloud Hosted

I've made Keeper easy to self-host, but whether you simply want to support the project or don't want to deal with the hassle or overhead of configuring and running your own infrastructure cloud hosting is always an option.

Head to keeper.sh to get started with the cloud-hosted version. Use code README for 25% off.

| | Free | Pro (Cloud-Hosted) | Pro (Self-Hosted) | | --------------------- | ---------- | ------------------ | ----------------- | | Monthly Price | $0 USD | $5 USD | $0 | | Annual Price | $0 USD | $42 USD (-30%) | $0 | | Refresh Interval | 30 minutes | 1 minute | 1 minute | | Source Limit | 2 | ∞ | ∞ | | Destination Limit | 1 | ∞ | ∞ |

Self Hosted

By hosting Keeper yourself, you get all premium features for free, can guarantee data governance and autonomy, and it's fun. If you'll be self-hosting, please consider supporting me and development of the project by sponsoring me on GitHub.

There are seven images currently available, two of them are designed for convenience, while the five are designed to serve the granular underlying services.

[!NOTE]

Migrating from a previous version? If you are upgrading from the older Next.js-based release, see the migration guide for environment variable changes. The new web server will also print a migration notice at startup if it detects old environment variables.

Environment Variables

| Name | Service(s) | Description | | ------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | DATABASE_URL | api, cron, worker, mcp | PostgreSQL connection URL.<br><br>e.g. postgres://user:pass@postgres:5432/keeper | | REDIS_URL | api, cron, worker | Redis connection URL. Must be the same Redis instance across all services.<br><br>e.g. redis://redis:6379 | | WORKER_JOB_QUEUE_ENABLED | cron | Required. Set to true to enqueue sync jobs to the worker queue, or false to disable. If unset, the cron service will exit with a migration notice. | | BETTER_AUTH_URL | api, mcp | The base URL used for auth redirects.<br><br>e.g. http://localhost:3000 | | BETTER_AUTH_SECRET | api, mcp | Secret key for session signing.<br><br>e.g. openssl rand -base64 32 | | API_PORT | api | Port the Bun API listens on. Defaults to 3001 in container images. | | ENV | web | Optional. Runtime environment. One of development, production, or test. Defaults to production. | | PORT | web | Port the web server listens on. Defaults to 3000 in container images. | | VITE_API_URL | web | The URL the web server uses to proxy requests to the Bun API.<br><br>e.g. http://api:3001 | | COMMERCIAL_MODE | api, cron | Enable Polar billing flow. Set to true if using Polar for subscriptions. | | POLAR_ACCESS_TOKEN | api, cron | Optional. Polar API token for subscription management. | | POLAR_MODE | api, cron | Optional. Polar environment, sandbox or production. | | POLAR_WEBHOOK_SECRET | api | Optional. Secret to verify Polar webhooks. | | ENCRYPTION_KEY | api, cron, worker | Key for encrypting CalDAV credentials at rest.<br><br>e.g. openssl rand -base64 32 | | RESEND_API_KEY | api | Optional. API key for sending emails via R

View on GitHub
GitHub Stars911
CategoryDevelopment
Updated56m ago
Forks26

Languages

TypeScript

Security Score

100/100

Audited on Mar 27, 2026

No findings