Inferensys

Prompt

Recurring Event Rule Normalization Prompt Template

A practical prompt playbook for converting natural language recurrence descriptions into validated RRULE strings and structured recurrence objects in production AI workflows.
Developer doing prompt engineering on laptop, prompt variations visible on screen, casual coding session.
PROMPT PLAYBOOK

When to Use This Prompt

Define the job, reader, and constraints for the Recurring Event Rule Normalization Prompt Template.

This prompt is for calendar integration engineers and scheduling platform developers who need to convert natural language recurrence descriptions into structured, machine-readable rules. The core job is to take a user-facing string like 'every other Tuesday until the end of the year' and produce a standards-compliant RRULE (RFC 5545), a human-readable confirmation, and a flag for any unsupported patterns. This is a normalization task, not a scheduling engine. The prompt assumes the input is a single recurrence description and the output is a single structured object ready for ingestion into a calendar system or event store.

Use this prompt when you have a reliable natural language input and need a deterministic, validatable output. It is designed for a backend processing pipeline where a user's free-text rule is passed to an LLM before being stored in a database or sent to a calendar API. The prompt includes explicit instructions to validate against RFC 5545, which means it is suitable for systems that must interoperate with standard calendar clients (Google Calendar, Outlook, iCal). Do not use this prompt for generating event instances (expansion), resolving conflicts, or handling complex exception dates. Those are separate scheduling problems that belong in application code, not in a normalization prompt.

Before integrating this prompt, ensure you have a clear contract for what your system considers 'unsupported.' The prompt includes a flag for patterns it cannot normalize, but you must define the boundary. For example, 'every payday' or 'whenever the moon is full' should be flagged, not hallucinated. The next step after reading this playbook is to copy the template, define your [UNSUPPORTED_PATTERNS] list, and run it against a golden test set of 50+ recurrence descriptions that include edge cases like leap year rules, monthly-by-day patterns, and interval limits.

PRACTICAL GUARDRAILS

Use Case Fit

Where the Recurring Event Rule Normalization Prompt works, where it breaks, and what you must have in place before relying on it.

01

Strong Fit: Calendar Integration Pipelines

Use when: ingesting user-facing natural language recurrence descriptions (e.g., 'every other Tuesday', 'monthly on the 15th') into calendar systems that require RFC 5545 RRULE strings. Guardrail: always validate the generated RRULE against an RFC 5545 parser before storing; reject rules that fail to parse rather than silently corrupting the calendar.

02

Poor Fit: Unbounded Natural Language

Avoid when: users can describe recurrence patterns that have no RRULE equivalent, such as 'every payday', 'whenever the board meets', or 'during school terms'. Guardrail: require the prompt to output an unsupported_pattern flag and a human-readable explanation; route flagged outputs to a manual review queue instead of guessing.

03

Required Inputs: Anchor Context

Risk: recurrence rules depend on a start date, timezone, and sometimes an end condition. Without these, the model may hallucinate defaults. Guardrail: always provide [START_DATE], [TIMEZONE], and [END_CONDITION] as explicit input fields; never rely on the model to infer them from context alone.

04

Operational Risk: Silent Compliance Failures

Risk: a generated RRULE may be syntactically valid but semantically wrong—producing events on the wrong day or skipping occurrences. Guardrail: include a human_readable_confirmation field in the output schema and display it to the user for verification before saving; log all confirmations for audit.

05

Operational Risk: Timezone Drift

Risk: recurrence rules without explicit timezone anchoring can shift across DST boundaries, causing events to land at unexpected times. Guardrail: always embed the IANA timezone in the RRULE using the TZID parameter; test generated rules against DST transition dates in your eval suite.

06

Poor Fit: High-Volume Unsupervised Ingestion

Avoid when: processing thousands of recurrence descriptions per minute without human review. Guardrail: implement a confidence threshold; route low-confidence normalizations to a dead-letter queue for manual inspection. Never auto-commit unverified RRULE strings to production calendars at scale.

PROMPT PLAYBOOK

Copy-Ready Prompt Template

A reusable prompt template with square-bracket placeholders that converts natural language recurrence descriptions into structured RRULE strings and human-readable confirmations.

The prompt template below is designed to be dropped into your application's model call. It accepts a natural language recurrence description, optional context like a start date or timezone, and a set of constraints, and returns a structured JSON object containing the normalized RRULE, a human-readable confirmation, and flags for unsupported patterns. All placeholders use square brackets and are meant to be replaced by your application logic before the request is sent to the model.

text
You are a recurrence rule normalization engine. Your job is to convert natural language descriptions of repeating events into RFC 5545 compliant RRULE strings.

## INPUT
Natural language recurrence description:
[RECURRENCE_DESCRIPTION]

Optional context:
- Event start date (ISO 8601): [START_DATE]
- Timezone: [TIMEZONE]
- Known constraints: [CONSTRAINTS]

## OUTPUT SCHEMA
Return ONLY valid JSON matching this schema:
{
  "rrule": "string (RFC 5545 RRULE, or null if unsupported)",
  "human_readable": "string (plain English confirmation of the recurrence pattern)",
  "is_supported": "boolean (false if the pattern cannot be expressed as a standard RRULE)",
  "unsupported_reasons": ["string (list of reasons why the pattern is unsupported, empty if supported)"],
  "warnings": ["string (non-blocking concerns like DST ambiguity, empty if none)"],
  "confidence": "number between 0.0 and 1.0"
}

## RULES
1. Generate RRULE strings compliant with RFC 5545.
2. Use the DTSTART from [START_DATE] if provided; otherwise omit DTSTART from the RRULE.
3. If the recurrence pattern cannot be expressed as a standard RRULE (e.g., 'every last weekday of the month that is not a holiday'), set is_supported to false and leave rrule as null.
4. Include a human_readable confirmation that a non-technical user could verify.
5. Flag any ambiguities in the warnings array (e.g., 'biweekly' could mean twice a week or every two weeks — state which interpretation was used).
6. If the description is vague or incomplete, set confidence below 0.8 and explain in warnings.
7. Do not invent dates, times, or recurrence details not present in the input.

## EXAMPLES
Input: "Every Monday at 9am starting January 6, 2025"
Output:
{
  "rrule": "DTSTART:20250106T090000\nRRULE:FREQ=WEEKLY;BYDAY=MO",
  "human_readable": "Every Monday at 9:00 AM starting January 6, 2025",
  "is_supported": true,
  "unsupported_reasons": [],
  "warnings": [],
  "confidence": 0.98
}

Input: "Every other Tuesday and Thursday until December"
Output:
{
  "rrule": "DTSTART:20250101T000000\nRRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,TH;UNTIL=20251231T235959",
  "human_readable": "Every other week on Tuesday and Thursday until December 31, 2025 (assuming start date of January 1, 2025 and end of December)",
  "is_supported": true,
  "unsupported_reasons": [],
  "warnings": ["Start date not provided, assumed January 1, 2025", "End date not specified, assumed December 31, 2025"],
  "confidence": 0.75
}

To adapt this template for your system, replace each square-bracket placeholder with values from your application context. The [RECURRENCE_DESCRIPTION] field should contain the raw user input or natural language text. [START_DATE] and [TIMEZONE] should be injected from your event or calendar record when available. The [CONSTRAINTS] field can carry business rules such as 'no weekend events' or 'only future dates'. If your application already has a known output schema, replace the JSON schema block with your own contract. For high-volume production use, add a post-processing step that validates the RRULE string against an RFC 5545 parser before storing it, and log any outputs where is_supported is false or confidence falls below your threshold for human review.

IMPLEMENTATION TABLE

Prompt Variables

Placeholders required by the Recurring Event Rule Normalization prompt. Replace each with a concrete value or wire it to an upstream data source before sending the request.

PlaceholderPurposeExampleValidation Notes

[RECURRENCE_DESCRIPTION]

Natural language description of the repeating event pattern to normalize.

Every other Tuesday at 10am, starting March 1st 2025, until end of year.

Required. Must be a non-empty string. Reject if input is only whitespace or a single word without temporal meaning.

[START_DATE]

Anchor date for the recurrence rule. Used as DTSTART in the generated RRULE.

2025-03-01

Required. Must parse as ISO 8601 date (YYYY-MM-DD). Reject if missing or if date is nonsensical (e.g., year 0000).

[TIMEZONE]

IANA timezone identifier for the event. Used to resolve ambiguous local times and DST transitions.

America/Chicago

Required. Must be a valid IANA timezone string. Validate against a known timezone list. Reject free-text like 'Central Time'.

[OUTPUT_FORMAT]

Target output structure: 'rrule_string', 'structured_object', or 'both'.

both

Required. Must be one of the three allowed enum values. Reject any other value. Default to 'both' if null.

[UNSUPPORTED_PATTERN_ACTION]

Behavior when the description contains a recurrence pattern that cannot be expressed in RRULE.

flag_and_continue

Required. Must be 'flag_and_continue', 'error', or 'best_effort'. Reject unknown values. Controls whether the prompt returns a partial result or aborts.

[MAX_RRULE_LENGTH]

Maximum character length for the generated RRULE string before truncation is flagged.

500

Optional. Must be a positive integer if provided. If null or missing, default to 500. Reject negative values or zero.

[LOCALE_HINTS]

Locale context for resolving week start day, holiday references, or regional date expressions in the description.

en-US

Optional. Must be a BCP 47 language tag if provided. If null, default to 'en-US'. Reject malformed tags.

[ADDITIONAL_CONSTRAINTS]

Extra business rules or constraints to apply during normalization, such as excluding specific dates or capping occurrences.

Exclude 2025-07-04. Maximum 12 occurrences.

Optional. If provided, must be a non-empty string. If null, no extra constraints are applied. Validate that constraints do not contradict the recurrence description.

PROMPT PLAYBOOK

Implementation Harness Notes

How to wire the Recurring Event Rule Normalization prompt into a production scheduling or calendar integration pipeline.

This prompt is designed to sit inside a post-extraction normalization layer, not as a direct user-facing chatbot. The typical caller is a calendar integration service, a scheduling API backend, or a data ingestion pipeline that has already extracted a natural language recurrence description from an email, a meeting transcript, a booking form, or a legacy system export. The caller should pass that extracted text as [RECURRENCE_DESCRIPTION] along with an optional [ANCHOR_TIMESTAMP] to resolve relative references like 'every other Monday starting next week.' The prompt returns a structured JSON payload containing a validated RRULE string, a human-readable confirmation, and an unsupported_patterns flag. Do not use this prompt for real-time chat interactions where the user is iteratively refining a recurrence rule; a multi-turn interface with a structured recurrence builder is more appropriate for that use case.

Wire the prompt into a stateless async worker or a request-response API endpoint. The application layer should enforce a strict JSON schema on the model's response before it reaches any downstream system. If the response fails schema validation—missing required fields, malformed RRULE syntax, or a normalized_rrule that does not parse as valid RFC 5545—the harness should retry once with the validation error injected into the [PREVIOUS_ERRORS] placeholder. After a second failure, log the full input, output, and validation trace, then route to a human review queue. For high-volume pipelines, consider batching multiple descriptions into a single request with a JSON array input and a corresponding array output schema to reduce API overhead, but keep batch sizes small (5-10 items) to avoid confusing the model across unrelated recurrence patterns.

Model choice matters here. Use a model with strong code and structured output capabilities, such as gpt-4o, claude-3-5-sonnet, or an equivalent. Avoid smaller or older models that may hallucinate RRULE property names or mishandle BYDAY ordinal values. Set temperature=0 to maximize deterministic RRULE generation. Enable structured outputs or JSON mode if the provider supports it, and always validate the RRULE string against an RFC 5545 parser library (such as rrule.js or dateutil.rrule in Python) before persisting the result. The unsupported_patterns field is a critical safety valve: if the model flags a pattern as unsupported, your application must not silently drop it. Instead, store the original description alongside the flag and surface it in an admin review interface so a human can author the correct RRULE or decide on an alternative representation.

For observability, instrument the harness with metrics on validation pass rate, retry rate, unsupported pattern frequency, and human review queue depth. Log every input description, the generated RRULE, the human-readable confirmation, and the validation result. This trace data is essential for debugging edge cases—such as 'every last weekday of the month' or 'biweekly on the 31st'—that may parse correctly but produce unexpected scheduling behavior. Set up a periodic eval run against a golden dataset of 50-100 recurrence descriptions with known-correct RRULE outputs, including tricky cases like monthly-by-day with skip logic, yearly patterns with timezone-aware exclusions, and descriptions that contain contradictory constraints. Run this eval on every prompt version change and on every model provider upgrade to catch regressions before they affect production calendars.

PRACTICAL GUARDRAILS

Common Failure Modes

Recurring event normalization is brittle because natural language is ambiguous and RRULE syntax is strict. These are the most common production failures and how to prevent them before they corrupt a calendar system.

01

Silent RRULE Syntax Violations

Risk: The model generates a string that looks like an RRULE but violates RFC 5545 (e.g., invalid property order, missing required parts, or illegal character combinations). Downstream parsers reject it silently or with cryptic errors. Guardrail: Always run the output through a strict RFC 5545 validator before storage. If validation fails, route to a repair prompt with the validator's error message as context, not a generic retry.

02

COUNT and UNTIL Collision

Risk: The model includes both COUNT and UNTIL in the same RRULE, which is explicitly forbidden by the spec. This often happens when the user says 'for the next 10 weeks' and the model also calculates an end date. Guardrail: Add a post-processing check that detects dual presence and removes the less specific constraint based on a deterministic rule (e.g., prefer UNTIL if both exist). Log the collision for prompt improvement.

03

Timezone Assumption Drift

Risk: The user says 'every Monday at 9 AM' without specifying a timezone. The model assumes UTC or its training-data default, producing events at the wrong local time after DST changes. Guardrail: Require a timezone input field. If missing, inject the system's default timezone explicitly into the prompt as [DEFAULT_TIMEZONE] and include a tzid parameter in the output. Never let the model guess.

04

Unsupported Pattern Hallucination

Risk: The user describes a recurrence like 'every other weekend' or 'the last weekday of the month' that requires complex BYDAY and BYSETPOS combinations. The model confidently generates an incorrect or incomplete rule instead of flagging it. Guardrail: Include a required is_fully_supported boolean in the output schema. Pair the prompt with a test suite of known-unsupported phrases. If false, route to a human review queue or a simpler confirmation prompt.

05

Interval Misinterpretation from Natural Language

Risk: Phrases like 'every other week' or 'bi-weekly' are ambiguous (every two weeks vs. twice a week). The model picks one arbitrarily, leading to incorrect schedules. Guardrail: Add a disambiguation_note field to the output schema. If the input contains known-ambiguous terms, force the model to state its interpretation explicitly. Surface this note in the UI for user confirmation before saving.

06

Start Date and Rule Mismatch

Risk: The DTSTART value doesn't align with the recurrence pattern (e.g., DTSTART is a Tuesday but the rule says 'every Monday'). The RRULE is technically valid but logically broken. Guardrail: Implement a semantic validator that checks if DTSTART matches the first instance defined by the BYDAY rule. If mismatched, flag for correction and suggest adjusting DTSTART to the next valid occurrence.

IMPLEMENTATION TABLE

Evaluation Rubric

Criteria for evaluating the quality of normalized RRULE outputs before integrating into production scheduling systems.

CriterionPass StandardFailure SignalTest Method

RFC 5545 Compliance

Output RRULE string parses without error by an RFC 5545 validator

Validator throws parse error or rejects the string

Run output through a standard iCalendar parsing library (e.g., python-dateutil rrulestr) and confirm no exceptions

Semantic Equivalence

Generated RRULE describes the same recurrence pattern as the natural language input

RRULE generates occurrences that conflict with the input description (e.g., wrong day, wrong interval)

Generate the next 5 occurrence dates from the RRULE and compare against manually interpreted expected dates from the input

Human-Readable Confirmation Accuracy

The confirmation text correctly restates the recurrence rule in plain language without contradiction

Confirmation text describes a different schedule than the RRULE or input text

Pairwise comparison by a second LLM judge or human reviewer checking for factual consistency between input, RRULE, and confirmation

Unsupported Pattern Flagging

Inputs containing non-RRULE-compatible patterns (e.g., 'every weekday except holidays') are flagged with unsupported_reason populated

Flag is false for an unsupported pattern, or true with an empty or irrelevant reason

Test with a curated set of 10 known-unsupported recurrence descriptions and verify flag=true and reason is non-empty and relevant

COUNT and UNTIL Mutual Exclusivity

Output RRULE never contains both COUNT and UNTIL in the same rule

Both COUNT and UNTIL are present in the RRULE string

String search for 'COUNT=' and 'UNTIL=' in the output; assert not both found

Timezone Handling

DTSTART and any timezone-sensitive parts reflect the input timezone context or UTC when unspecified

RRULE produces occurrences shifted by hours due to ignored or defaulted timezone

Inject inputs with explicit timezone context (e.g., 'every Monday at 9am EST') and verify DTSTART includes the correct TZID or UTC offset

Input Ambiguity Handling

Ambiguous inputs (e.g., 'biweekly' without clarification) produce a confidence score below threshold or a clarification request

Model confidently produces a single RRULE for a genuinely ambiguous input

Test with 'biweekly meeting' and check if confidence < 0.9 or output includes a clarification note rather than a single RRULE

Edge Case: Month-End Rules

Rules like 'last day of month' produce BYMONTHDAY=-1 or equivalent correct representation

Output uses BYMONTHDAY=31 or other incorrect fixed day

Test with 'monthly on the last day' and verify BYMONTHDAY=-1 in the RRULE

ADAPTATION OPTIONS

Adapt This Prompt

How to adapt

Use the base prompt with a single model call and minimal post-processing. Accept the RRULE string and human-readable confirmation as-is. Skip strict RFC 5545 validation in the prompt layer—validate in application code instead.

Watch for

  • Model inventing RRULE properties not present in the input (e.g., adding COUNT when only UNTIL was implied)
  • Overly broad interpretation of vague phrases like 'every other week' without asking for clarification
  • Missing the unsupported-pattern flag when the recurrence is too complex for RRULE
Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.