CLI tool
pimutils/khal avatar
pimutils/khal

khal: the readme titles its own feature list as limitations

:calendar: CLI calendar application

3,067 stars236 forksPythonMIT

At a glance

What is it?
Khal is a terminal calendar that does not talk to any server itself. It reads and writes iCalendar files into a local directory, and a separate tool pushes those to a standards-based server, which is a deliberate choice that keeps the calendar usable offline and keeps one process out of your credentials. The page is unusually honest about the result: its capability list is headed with a line telling you it is really a list of limitations.
Who is it for?
Use khal if you want a calendar you can drive from the keyboard, if your calendars are already in a format a sync tool can push, and if you want your events on disk in a standard format rather than inside a vendor's database. Three things to weigh.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 5, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The capability list is headed with a line telling you it is really a limitations list

The most unusual thing on the page is structural. The section title reads features, followed immediately by a parenthetical correction. And the list under it mixes both kinds of statement in a way that is more useful than a feature list would have been. What it can do: read and write events into a local directory in a standard calendar format, so that a separate synchronisation tool can push them to a server that speaks the standard protocol, for example a CalDAV host; add events quickly; and open an interactive mode for browsing and editing calendars and events. What it cannot do, in the same list: no support yet for editing the time zone of an event; it needs a recent Python; and it runs on all major operating systems, with the exception of one, stated as a footnote rather than a bullet. That structure is the clearest signal of how the project sees itself, and it is a good reason to read the list straight through instead of skimming it.

Two console commands, and the interactive one is the reason people stay

The manifest binds two entry points rather than one:

code
khal = "khal.cli:main_khal"
ikhal = "khal.cli:main_ikhal"

The second is the interactive program, a full-screen browser and editor for calendars and events, and the readme gives it exactly one line in a list that otherwise describes the command-line side. That undersells it. For a tool with no web interface and no graphical one, a curses application where you can move between calendars, open an event and edit it is the entire user experience, and the classifier in the manifest says as much by declaring the environment to be a console application built on a curses library. That library also shows up in the test configuration, where a warning filter suppresses a deprecation notice about modules moving, with a comment explaining that a property-based testing tool triggers the warning while walking the library's internals. A project that has to pin a suppression to keep its own suite green against a dependency's internals is a project that has been running that suite for a long time.

Three time libraries, one of which the language now provides

The dependency list carries a time zone database library, a local time zone detector and a date parsing library, all three at once. Only the detector has an explicit floor. A separate optional entry point exists to let the process rename itself in the process list, which is how the tool shows up under a readable name rather than its interpreter path. Since the language itself has shipped a first-class time zone database in its standard library for several releases now, carrying an external database alongside a detector and a parser is the kind of thing that costs install size and a dependency to keep current. It is also exactly the residue you find in a project with a decade of history, and the page does not explain the choice. It is worth noticing because the readme's stated limitation, that you cannot yet edit an event's time zone, is the one capability you would expect that stack to have made easy.

One dependency has a floor from a much older generation and no ceiling

The command line parser is required at a floor of three point two with nothing above it, so an installer will take any version from that generation through to the present. The rest of the list is not uniformly loose. The calendar library carries an explicit floor and an explicit ceiling below its next major, the time zone detector carries a floor, and the terminal toolkit carries a floor. So this is one line where the range was left open rather than a general looseness. For a console entry point that has to keep working across a range of Python versions, a floor that permissive buys compatibility with environments nobody runs any more and promises you nothing about what you actually get. It is the kind of line that survives because widening a floor is harmless on the machines the maintainer uses, and it only matters to somebody building a lockfile for a fleet.

Two of the six install commands deviate from the obvious

The installation section gives one example per platform and points at a package index for the authoritative list of versions per distribution, which is the right thing to do. Two of the six examples will still surprise you. The BSD example installs a package whose name is not the project's name, with a language prefix in front of it, so a reader copying commands across platforms types something that does not exist. The Nix example uses the environment-installation command that predates the modern profile and shell interfaces, so it will not be what a current documentation page would tell you to type. Neither command is wrong, and both are the kind of instruction that goes stale quietly, because nothing in continuous integration runs the install lines from the readme. The package index link is where to check before trusting any of the six.

The route labelled install latest version gives you the tip of the branch

The last installation route is a package-manager command pointing at the project's own repository URL, with no revision specified, under a heading that says to install the latest version. What you get is the current default branch. That is a wider gap than it sounds here, because the newest tagged release is from February 2024 while the branch has received commits steadily since, so the difference between the newest release and the newest source is well over a year of work. The heading is not dishonest, since it does say latest, but the distinction between a release and a source build is the one people get wrong, and the page does not add a warning. The contributing section lists creating packages for your own operating system as one of the most appreciated contributions, which is a hint that the packaged builds are expected to lag the source and that somebody maintaining a distribution package is doing real work.

A release file sits in the root, and the licence text is duplicated in two places

Two housekeeping details point the same way. The file that handles publishing releases is named like a workflow and sits in the repository root rather than in the directory the platform reads, so whatever starts it, the platform is not starting it from that location. And the licence is declared in the manifest with a pointer to a file inside the documentation sources, while the licence text itself also lives in the root under a filename from an older free-software convention, carrying a copyright range that ends four years before the last recorded commit. Neither detail breaks an installation, and both are the sort of thing you notice only when you are checking where the parts live before trusting a build. The rest of the repository is conventional and careful: a changelog, a code of conduct, a contributing guide, an authors file, a sample configuration, a coverage configuration alongside the coverage service badge, and a readthedocs configuration.

Editorial conclusion

Use khal if you want a calendar you can drive from the keyboard, if your calendars are already in a format a sync tool can push, and if you want your events on disk in a standard format rather than inside a vendor's database. Three things to weigh. The sync half is somebody else's project, so you are adopting two tools and one configuration format. The interactive mode is a full event browser and editor, which is the reason most people stay, and it is not described in the readme beyond a single line. And the version story: the newest tagged release is from February 2024 while the branch has moved steadily since, so the install route labelled latest gives you the tip rather than the release. If you want the release, install a packaged build. The default branch was last pushed on 2026-09-28.

Frequently asked questions

How do I display a calendar in the terminal?

khal is built for exactly that, and it installs as a plain command-line program with a second command that opens a full-screen interactive browser and editor for calendars and events. It does not connect to a server itself: it reads and writes calendar files in a local directory in a standard format, and you use a separate synchronisation tool to push those to a standards-based server.

Does khal sync with Google Calendar or CalDAV servers?

It can, through a separate synchronisation tool rather than through khal itself. khal reads and writes calendar files to a local directory, and that tool pushes them to a variety of other programs, with standards-based servers given as the example. The alternative tool the page names works only with one vendor's calendar, which is one of the two reasons it lists.

What are the alternatives to khal?

The page names two and gives a reason for each. One has no offline storage and a slightly different scope. The other works only with one vendor's calendar service. Both limitations are stated as reasons you might look elsewhere rather than as criticism, which makes the section one of the more honest ones on the page.

Does khal run on Windows?

No, and the page says so in a footnote rather than in the bullet list. The claim is that it should run on all major operating systems, followed immediately by an exception for that one. The packaging examples cover Linux distributions, macOS through a package manager, the BSDs and Nix, and there is no Windows example anywhere in the installation section.

What version of Python does khal need?

The readme says a recent Python, phrased as three point ten or newer. The manifest is stricter than that: it sets a floor of three point ten and a ceiling below three point fifteen, and its classifiers enumerate interpreter versions from three point ten through three point fourteen. So the upper bound is real and is the part the readme does not mention.

Official sources

  1. License: MIT
  2. pimutils/khal on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pimutils-khal.svg)](https://hysenlabs.com/projects/pimutils-khal)