Skip to content

pimalaya/tcal

tcal Documentation Matrix Mastodon

CLI & lib to edit iCalendars as ergonomic TOML.

$ tcal edit --event
summary = "Check for tcal issues"
categories = ["pimalaya", "cli"]
url = "https://github.com/pimalaya/tcal/issues"
organizer = "pimalaya.org@posteo.net"
class = "public"
priority = 5
status = "confirmed"
recurrence.frequency = "daily"
recurrence.interval = 1

[[attendee]]
display-name = "Pimalaya"

[[alarm]]
summary = "Go check daily tcal issues"
action = "display"
trigger.min = 5

Output:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Pimalaya//tcal//EN
BEGIN:VEVENT
UID:1f34e439-ca07-446f-af28-f5b7d3afcfc8
DTSTAMP:20260613T211938Z
SUMMARY:Check for tcal issues
CATEGORIES:pimalaya,cli
URL:https://github.com/pimalaya/tcal/issues
ORGANIZER:mailto:pimalaya.org@posteo.net
CLASS:PUBLIC
PRIORITY:5
STATUS:CONFIRMED
RRULE:FREQ=DAILY;INTERVAL=1
BEGIN:VALARM
SUMMARY:Go check daily tcal issues
ACTION:DISPLAY
TRIGGER:-PT5M
END:VALARM
END:VEVENT
END:VCALENDAR

This repository ships two interfaces:

  • Rust library to generate iCalendar from/to TOML projection
  • CLI to print and/or edit TOML template using $EDITOR

Table of contents

Features

  • Partial no_std support
  • iCalendar from/to TOML projection, backed by calcard (RFC 5545).
  • Friendly keys and values: cryptic names become readable TOML keys.
  • Structured recurrence and duration.
  • Discoverable properties: prints all available properties with empty values by default, fill the ones you need.
  • Minimal, lossless diffs: apply patches the original text through a format-preserving editor, re-rendering only the lines you changed.

Installation

Pre-built binary

tcal is not yet released, therefore the only way to get a pre-built binary is to check out the releases GitHub workflow and look for the Artifacts section.

Note

Such binaries are built with the default cargo features. If you need specific features, please use another installation method.

Cargo

cargo install tcal --locked --features cli

You can also use the git repository for a more up-to-date (but less stable) version:

cargo install --locked --git https://github.com/pimalaya/tcal.git

To use tcal as a library, add it to your Cargo.toml:

[dependencies]
tcal = "0.0.1"

The library has no default features: it is a slim no_std (plus alloc) build with no clap, no editor integration, just the project / apply projection over a calcard ICalendar. The CLI lives behind the opt-in cli feature (enabled above with cargo install --features cli).

Nix

If you have the Flakes feature enabled:

nix profile install github:pimalaya/tcal

Or run without installing:

nix run github:pimalaya/tcal -- template < event.ics

Sources

git clone https://github.com/pimalaya/tcal
cd tcal
nix run

Usage

Library

Project a calendar event to TOML, then fold edits back:

use tcal::{ical, template};

let input = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nSUMMARY:Lunch\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n";
let calendar = ical::parse(input).unwrap();

// Project the whole calendar to a TOML scaffold ([[block]] per component).
// (project_with(&calendar, &["event".to_owned()]) narrows to chosen types.)
let scaffold = template::project(&calendar);
assert!(scaffold.contains("summary = \"Lunch\""));

// After the user edits the scaffold, fold it back onto the original text:
// only changed lines are re-rendered, everything else stays byte-for-byte.
let edited = scaffold.replace("Lunch", "Team lunch");
let updated = template::apply(input, &edited).unwrap();
assert!(updated.contains("SUMMARY:Team lunch"));

CLI

Print a blank, fully-documented template:

tcal template

Project an existing event to TOML (path, stdin via -, or literal contents):

tcal template event.ics
tcal template - < event.ics
tcal template --event event.ics              # just the event, flattened
tcal template --event --todo event.ics       # only events and to-dos

Edit an event in $EDITOR. With a file source, the result is written back in place; otherwise it goes to stdout (or --output):

tcal edit event.ics
tcal edit - < event.ics > updated.ics
tcal template | $EDITOR /dev/stdin   # inspect the scaffold first

Start a new event from scratch and write it out:

tcal edit --output meeting.ics

FAQ

Which calendar components does tcal edit?

All of them, as [[blocks]]: event, todo, journal, free-busy, timezone (with nested [[event.alarm]], [[timezone.standard]]/[[timezone.daylight]]). Every type is listed (actual instances filled, an empty example for each absent type); repeated components show as repeated blocks. The per-type flags narrow the view: one (--event) flattens just that type at the root, several (--event --todo) show only those as blocks, and a filtered edit only touches the types it shows (so the rest of the calendar is preserved on save). Component types tcal does not model, and unmodeled properties, are kept verbatim but not surfaced.

How do I write dates and times?

Use YYYY-MM-DD HH:MM for a timed event (2026-06-13 14:00), YYYY-MM-DD alone for an all-day event, and append UTC for a UTC value. For a zoned time, set the adjacent date-start-tz / date-end-tz key to an IANA zone like Europe/Paris; leave it empty for UTC or floating time. A raw iCalendar value (20260613T140000) is accepted too.

How does tcal edit pick the editor?

The edit crate resolves $VISUAL first, then $EDITOR, then an OS default. tcal does not expose a config override: set VISUAL / EDITOR in your shell rc file.

Will tcal reformat my whole calendar on edit?

No. apply patches the original text through a format-preserving editor (the iCalendar analog of toml_edit): only the lines of modeled fields you actually changed are re-rendered, so the diff is minimal. Folding, parameter casing, property order and line endings of every untouched line are kept byte-for-byte.

What happens to properties and components tcal does not list?

They are kept verbatim. The scaffold surfaces the modeled component vocabulary, but apply carries every unmodeled property (DTSTAMP, SEQUENCE, custom X-*) and every unmodeled component type straight from the original calendar into the result. Unmodeled properties inside an edited component are likewise preserved (removing a whole block, of course, removes the component and everything in it).

How do I debug the CLI?

Use --log <level> where <level> is one of off, error, warn, info, debug, trace:

tcal --log trace template event.ics

The RUST_LOG environment variable, when set, overrides --log and supports per-target filters (see the env_logger documentation). RUST_BACKTRACE=1 enables full error backtraces. Logs are written to stderr.

License

This project is licensed under either of:

at your option.

AI disclosure

This project is developed with AI assistance. This section documents how, so users and downstream packagers can make informed decisions.

  • Tools: Claude Code (Anthropic), Opus 4.8, invoked locally with a persistent project-scoped memory and a small set of repo-specific rules.
  • Used for: Refactors, mechanical multi-file edits, boilerplate (feature gates, error enums, derive macros, trait impls), test scaffolding, doc polish, exploratory design conversations.
  • Not used for: Engineering, critical code, git manipulation (commit, merge, rebase…), real-world tests.
  • Verification: Every AI-assisted change is read, compiled, tested, and formatted before commit (nix develop --command cargo check / cargo test / cargo fmt). Behavioural correctness is verified against the relevant RFC or upstream spec, not assumed from the model output. Tests are never adjusted to fit AI-generated code; the code is adjusted to fit correct behaviour.
  • Limitations: AI models occasionally produce code that compiles and passes tests but is subtly wrong: off-by-one errors, missed edge cases, plausible but nonexistent APIs, stale RFC references. The verification workflow catches most of this; it does not catch all of it. Bug reports are welcome and taken seriously.
  • Last reviewed: 13/06/2026

Social

Sponsoring

nlnet

Special thanks to the NLnet foundation and the European Commission that have been financially supporting the project for years:

If you appreciate the project, feel free to donate using one of the following providers:

GitHub Ko-fi Buy Me a Coffee Liberapay thanks.dev PayPal

About

CLI & lib to edit iCalendars as ergonomic TOML, written in Rust

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Contributing

Stars

Watchers

Forks

Contributors