· 4 min read · Billy Lui

Introducing the Truth Engine: Deterministic RRULE Expansion

Recurring calendar events follow the iCalendar RRULE specification (RFC 5545). It’s a deceptively complex format that breaks LLMs in subtle ways.

Why RRULE expansion is hard

Consider a weekly standup: RRULE:FREQ=WEEKLY;BYDAY=MO;UNTIL=20261231T235959Z. Simple enough. But real-world RRULEs get complex fast:

  • DST transitions: A 9am meeting in America/New_York shifts its UTC offset twice a year. Naive implementations create phantom events or skip real ones.
  • BYSETPOS: FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1 means “last weekday of the month.” Most LLMs interpret this incorrectly.
  • EXDATE: Exception dates remove specific occurrences from the series. Missing one means showing a cancelled meeting as active.
  • Leap years: February 29th events only recur every 4 years. Some implementations silently skip them.
  • INTERVAL > 1: FREQ=WEEKLY;INTERVAL=2 means every other week. The anchor date matters — get it wrong and every occurrence shifts.

Why LLMs can’t do it

LLMs approach RRULE expansion as a text generation task. They predict what the next date “should be” based on the pattern. But RRULE expansion is a mathematical computation — the spec defines a deterministic algorithm.

When an LLM “expands” an RRULE, it’s guessing. When the Truth Engine expands an RRULE, it’s computing.

We tested this directly. We ran 5 real-world RRULEs through frontier LLMs and the Truth Engine. The results are stark — read the full side-by-side comparison. Here’s one example:

RRULE: FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,TH;COUNT=8 (biweekly on Tuesday and Thursday)

LLM: Generates occurrences every week, ignoring INTERVAL=2. Half the dates are wrong.

Truth Engine: Correctly skips alternate weeks. The 8 occurrences span 7 weeks, not 4.

The pattern repeats across all 5 tests. DST transitions, BYSETPOS, leap years, EXDATE — the LLM produces plausible-looking dates that fail RFC 5545 compliance. The Truth Engine produces correct dates every time.

The Truth Engine approach

The Truth Engine is a Rust library that implements RFC 5545 RRULE expansion with full spec compliance. It handles every edge case the spec defines:

  • DST-aware UTC conversion: The same wall-clock time produces different UTC values before and after a DST transition. The Truth Engine preserves wall-clock time and recomputes the UTC offset.
  • BYSETPOS with negative indices: BYSETPOS=-1 means “last in the set.” The set is computed per-period (per-month, per-year), then the index is applied. This requires computing all candidates first, then selecting.
  • EXDATE with timezone matching: Exception dates must match expanded instances exactly, accounting for timezone. A UTC EXDATE must be compared against timezone-converted instances, not raw local times.
  • Leap year filtering: BYMONTHDAY=29;BYMONTH=2 produces instances only when February 29 exists. No substitution to Feb 28 or March 1.
  • INTERVAL across frequency units: INTERVAL=2 on a weekly frequency skips every other week. The interval applies to the frequency, not to individual BYDAY values.

Testing with 9,000+ property-based tests

Unit tests check specific cases. Property-based tests check invariants across randomly generated inputs. The Truth Engine uses both.

The property-based tests verify invariants like:

  • Every expanded instance falls within the DTSTART-UNTIL range
  • Instances are always in chronological order
  • The count of instances never exceeds the RRULE’s COUNT parameter
  • Every instance respects the BYDAY, BYMONTH, BYMONTHDAY constraints
  • Given the same inputs, the Rust native, WASM, and Python bindings all produce identical output

9,000+ generated test cases means the engine has been tested against RRULE combinations that no human would think to write — unusual INTERVAL values, extreme BYSETPOS indices, RRULEs that span century boundaries. For a deeper look at how property-based testing catches calendar edge cases that unit tests miss, see Property-Based Testing for Calendar Engines.

Available on three platforms

# Rust (native)
cargo add truth-engine

# JavaScript/TypeScript (via WASM)
npm install @temporal-cortex/truth-engine

# Python (via PyO3 native bindings)
pip install truth-engine

The same Rust implementation powers all three packages. The JavaScript version compiles to WebAssembly, so it runs in browsers and Node.js with native-like performance. The Python version uses PyO3 for direct native bindings — no subprocess, no IPC overhead.

Every expansion is deterministic. Given the same RRULE and parameters, the Truth Engine always returns the same result — across platforms, across time.

Using it with Temporal Cortex

The Truth Engine powers the expand_rrule tool in the Temporal Cortex MCP server. Install the server and your AI agent gets deterministic RRULE expansion as one of 18 tools:

npx @temporal-cortex/cortex-mcp

The expand_rrule tool is a Layer 2 tool — it requires no network access and performs pure computation. You can also use the Truth Engine directly as a library in your own applications without the MCP server.

Open source

The Truth Engine is open source under MIT/Apache-2.0 dual license. It’s part of Temporal Cortex Core, available on crates.io, npm, and PyPI.

Browse the source on GitHub.