Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Fetch, compute, and format religious observance calendars for the three in-scope Abrahamic traditions of the Abrahamic Reference Engine: Judaism, Christianity, and Islam. Use this skill whenever an agent needs to retrieve religious holiday data, generate iCalendar (.ics) output, look up holiday descriptions for cross-tradition audiences, or produce a unified observance event list. Covers Hebcal API (Jewish), AlAdhan API (Islamic), TypeScript Computus algorithm (Christian -- Western and Orthodox)
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 100% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 79% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 178% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 214% | 0% |
OverKill Hill P³ · overkillhill.com · github.com/OKHP3
Fetch, compute, and format religious observance calendars for the Abrahamic Reference Engine.
Covers Judaism (Hebcal API), Christianity (Computus algorithm -- Western and Orthodox), and Islam (AlAdhan API). All sources are free and anonymous. No API key. No cost. Zero runtime dependencies beyond fetch.
the year before constructing provider URLs or date objects.
ObservanceEvent and retain the source,attribution, and caveat fields. Computed dates, provider dates, and missing dates must remain distinguishable.
Promise.allSettled for independent provider or month requests so oneoutage does not discard successful results. Surface partial failure in the UI or return metadata rather than hiding it.
credentialed, or unverified holiday API. Run the bundled Easter validator after algorithm changes.
caveat, and never present an estimated date as universally authoritative.
display the exact attribution string with the returned article URL.
.ics.Follow the bundled RFC 5545 line-folding and date rules.
Read these on demand -- only the file(s) you actually need for the current task:
| File | When to read | |------|-------------| | references/api-reference.md | Full API schemas and field details for Hebcal and AlAdhan; use when you need the complete response shape or want to understand all available query parameters | | references/computus.md | Computus algorithm derivation, edge cases, century correction, and multi-century validation dates; use when troubleshooting Easter date accuracy | | references/holiday-data.md | Extended WIKIPEDIA_ARTICLE_MAP entries and supplementary AlAdhan display name notes; use when adding a holiday not covered by the map in this file | | references/ics-spec.md | ICS format specification, RFC 5545 line-folding rules, calendar client compatibility notes, and VTIMEZONE considerations |
The SKILL.md sections below are sufficient for most implementation tasks. Reach for the reference files when you need depth beyond what is documented here.
A holiday is in scope if and only if it meets both criteria:
| Tradition | US Share | In Scope | |---|---|---| | Christianity | ~63% | Yes -- five denominational lenses | | Judaism | ~2% | Yes | | Islam | ~1% | Yes | | Hinduism | ~1% | No (not Abrahamic) | | Buddhism | ~1% | No (not Abrahamic) | | Baha'i | ~0.1% | No (Abrahamic but below threshold) |
Source: Pew Research Center -- https://www.pewresearch.org/religion/religious-landscape-study/
All holiday sources normalize to this shared interface:
typescriptinterface ObservanceEvent { id: string; // "{tradition}-{rawName}-{year}-{startDateISO}" title: string; // emoji-prefixed: "✡️ Rosh Hashanah" rawName: string; // without emoji: "Rosh Hashanah" emoji: string; // "✡️" | "✝️" | "☦️" | "☪️" tradition: 'judaism' | 'christianity' | 'islam'; denomination: 'all' | 'catholic' | 'orthodox' | 'protestant' | 'evangelical' | 'restorationist'; startDate: Date; endDate: Date; // equals startDate for single-day events isMultiDay: boolean; hebrewName?: string; // Jewish holidays only hijriDate?: string; // Islamic holidays only, e.g., "1 Muharram 1448 AH" sourceUrl?: string; // Hebcal permalink or Wikipedia URL source: 'hebcal' | 'aladhan' | 'algorithm'; wikiArticle?: string; // Wikipedia article title for description fetch (Section 5) }
typescriptexport const TRADITION_EMOJI = { judaism: '✡️', // U+2721 U+FE0F Star of David christianity_western: '✝️', // U+271D U+FE0F Latin Cross christianity_orthodox: '☦️', // U+2626 U+FE0F Orthodox Cross islam: '☪️', // U+262A U+FE0F Star and Crescent } as const;
Use ✝️ for Catholic, Mainline Protestant, Evangelical, and Restorationist events. Use ☦️ for Orthodox-specific events and dates.
No API key. CC BY 4.0. Free.
GET https://www.hebcal.com/hebcal?v=1&cfg=json&year={year}&maj=on&min=off&nx=off&mf=off&ss=on&mod=on&i=off&lg=s&m=50Parameters that matter:
maj=on -- major holidays (required)ss=on -- special Shabbatotmod=on -- modern Israeli holidays (Yom HaShoah, Yom HaAtzmaut)i=off -- Diaspora rules (not Israeli rules -- ARE targets US audience)min=off -- minor holidays off by default (expose as optional filter)typescriptasync function fetchJewishHolidays(year: number): Promise<ObservanceEvent[]> { const cacheKey = `are_hebcal_${year}`; const cached = sessionStorage?.getItem(cacheKey); if (cached) return JSON.parse(cached); const url = `https://www.hebcal.com/hebcal?v=1&cfg=json&year=${year}&maj=on&min=off&nx=off&mf=off&ss=on&mod=on&i=off&lg=s&m=50`; const res = await fetch(url); if (!res.ok) throw new Error(`Hebcal fetch failed: ${res.status}`); const data = await res.json(); const items: HebcalItem[] = (data.items || []).filter( (item: HebcalItem) => item.category === 'holiday' ); const events = normalizeHebcalItems(items, year); sessionStorage?.setItem(cacheKey, JSON.stringify(events)); return events; }
json{ "title": "Rosh Hashana 5787", "date": "2026-09-20", "hdate": "1 Tishrei 5787", "category": "holiday", "subcat": "major", "hebrew": "ראש השנה", "link": "https://www.hebcal.com/holidays/rosh-hashana-5787", "memo": "Jewish New Year" }
"Rosh Hashana 5787" → "Rosh Hashana"endDate to the last consecutive day with the same name; isMultiDay = true when span > 1hebrewName from hebrew fieldsourceUrl from link fieldwikiArticle from WIKIPEDIA_ARTICLE_MAP[normalizedName] (see Section 5)emoji = '✡️', tradition = 'judaism', denomination = 'all'Display in UI: "Calendar data via Hebcal.com (CC BY 4.0)" Link: https://www.hebcal.com
No API key. Free. GPL-3.0.
AlAdhan embeds holiday data in each day of the Gregorian-to-Hijri calendar response. Fetch all 12 months in parallel; collect days where date.hijri.holidays is non-empty.
GET https://api.aladhan.com/v1/gToHCalendar/{month}/{year}> WARNING -- use Promise.allSettled, NOT Promise.all. > AlAdhan occasionally drops individual month requests. > Promise.all fails fast and discards all 11 other successful months. > Promise.allSettled continues and collects partial results gracefully. > This is a hard requirement, not a suggestion.
typescriptasync function fetchIslamicHolidays(year: number): Promise<ObservanceEvent[]> { const cacheKey = `are_aladhan_${year}`; const cached = sessionStorage?.getItem(cacheKey); if (cached) return JSON.parse(cached); const months = Array.from({ length: 12 }, (_, i) => i + 1); const responses = await Promise.allSettled( months.map(m => fetch(`https://api.aladhan.com/v1/gToHCalendar/${m}/${year}`) .then(r => r.ok ? r.json() : Promise.reject(r.status)) ) ); const allDays: AladhanDay[] = responses.flatMap(result => result.status === 'fulfilled' ? result.value.data || [] : [] ); const events = normalizeAladhanDays(allDays, year); sessionStorage?.setItem(cacheKey, JSON.stringify(events)); return events; }
json{ "gregorian": { "date": "20-03-2026", "year": "2026", "month": { "en": "March" }, "day": "20" }, "hijri": { "date": "01-09-1447", "year": "1447", "month": { "en": "Ramaḍān", "number": 9 }, "day": "01", "holidays": ["Start of Ramadan"] } }
Only include days where at least one entry in holidays[] matches this allowed set:
typescriptconst ALADHAN_ALLOWED: Set<string> = new Set([ "Arafat (Haj) Day", "Eid-ul-Adha", "Islamic New Year", "Ashura", "Mawlid al-Nabi", "Al Isra' Wal Mi'raj", "Start of Ramadan", "Laylat al Qadr", "Eid ul Fitr", ]);
Discard any holiday string not in this set. Discard days where holidays is empty.
typescriptconst ALADHAN_DISPLAY_NAMES: Record<string, string> = { "Arafat (Haj) Day": "Day of Arafah", "Eid-ul-Adha": "Eid al-Adha", "Islamic New Year": "Islamic New Year (Muharram 1)", "Ashura": "Ashura", "Mawlid al-Nabi": "Mawlid al-Nabi (Prophet's Birthday)", "Al Isra' Wal Mi'raj": "Isra and Mi'raj (Night Journey)", "Start of Ramadan": "First Day of Ramadan", "Laylat al Qadr": "Laylat al-Qadr (Night of Power)", "Eid ul Fitr": "Eid al-Fitr", };
Eid al-Adha and Eid al-Fitr may appear across 2–3 consecutive days. Group consecutive days with the same normalized display name into a single event. Set endDate to the last day; isMultiDay = true.
Always display alongside Islamic events: > "Islamic dates are calculated using the Umm al-Qura method. Actual observance may vary by one day based on local moon sighting."
Display in UI: "Islamic calendar data via AlAdhan.com" Link: https://aladhan.com
No external API. Fully client-side. Zero dependencies.
typescriptfunction computeWesternEaster(year: number): Date { const a = year % 19; const b = Math.floor(year / 100); const c = year % 100; const d = Math.floor(b / 4); const e = b % 4; const f = Math.floor((b + 8) / 25); const g = Math.floor((b - f + 1) / 3); const h = (19 * a + b - d - g + 15) % 30; const i = Math.floor(c / 4); const k = c % 4; const l = (32 + 2 * e + 2 * i - h - k) % 7; const m = Math.floor((a + 11 * h + 22 * l) / 451); const month = Math.floor((h + l - 7 * m + 114) / 31); const day = ((h + l - 7 * m + 114) % 31) + 1; return new Date(year, month - 1, day); }
Validation: 2026 → April 5 | 2027 → March 28
typescriptfunction computeOrthodoxEaster(year: number): Date { const a = year % 4; const b = year % 7; const c = year % 19; const d = (19 * c + 15) % 30; const e = (2 * a + 4 * b - d + 34) % 7; const f = Math.floor((d + e + 114) / 31); const g = ((d + e + 114) % 31) + 1; // Julian result; add 13 days for 20th/21st century Gregorian conversion const result = new Date(year, f - 1, g + 13); return result; }
Validation: 2026 → April 12 | 2027 → May 2
Generate from the two Easter anchors, preserving denomination labels and stable event IDs. Read references/computus.md for the complete deterministic implementation, feast inventory, and validation dates.
No API key. Free. CC BY-SA 3.0. No external cost.
GET https://en.wikipedia.org/api/rest_v1/page/summary/{article_title}Fetch on user interaction only and cache by article title. Read references/api-reference.md for the error-safe fetch pattern and references/holiday-data.md for the complete article map. Do not pre-fetch all descriptions on calendar load.
Always display in UI: "Description via Wikipedia (CC BY-SA 3.0)" with link to the Wikipedia article URL returned by the API.
Generate client-side only. Preserve RFC 5545 all-day DATE semantics, use an exclusive end date, escape content, and include a stable UID. Read references/ics-spec.md for the full implementation and interoperability requirements.
| Data | Cache key | When to populate | When to invalidate | |---|---|---|---| | Hebcal annual result | are_hebcal_{year} | On first tab open for that year | Session end | | AlAdhan annual result | are_aladhan_{year} | On first tab open for that year | Session end | | Christian holidays | In-memory (computed) | On tab open | Never (deterministic) | | Wikipedia description | are_wiki_{articleTitle} | On first event click | Session end |
Use sessionStorage in browser contexts. In Node/agent contexts, use a simple in-memory Map.
Always include the following when presenting output from this skill:
| Source | Attribution text | |---|---| | Hebcal | "Calendar data via Hebcal.com (CC BY 4.0)" | | AlAdhan | "Islamic calendar data via AlAdhan.com" | | Algorithm | "Christian holiday dates computed per ecclesiastical calendar" | | Wikipedia | "Description via Wikipedia (CC BY-SA 3.0)" |
| Holiday | Year | Correct Date | |---|---|---| | Western Easter | 2026 | April 5 | | Western Easter | 2027 | March 28 | | Orthodox Easter | 2026 | April 12 | | Orthodox Easter | 2027 | May 2 | | Ash Wednesday | 2026 | February 18 | | Good Friday | 2026 | April 3 | | Pentecost | 2026 | May 24 | | Orthodox Christmas | any | January 7 | | Theophany | any | January 19 | | Rosh Hashanah | 2026 | September 20–21 | | Yom Kippur | 2026 | September 29 |
Fetch all observances for 2026:
typescriptconst [jewish, islamic] = await Promise.allSettled([ fetchJewishHolidays(2026), fetchIslamicHolidays(2026), ]); const christian = generateChristianHolidays(2026); const allEvents: ObservanceEvent[] = [ ...(jewish.status === 'fulfilled' ? jewish.value : []), ...(islamic.status === 'fulfilled' ? islamic.value : []), ...christian, ].sort((a, b) => a.startDate.getTime() - b.startDate.getTime());
Get description for a holiday:
typescriptconst description = await getHolidayDescription('Rosh Hashanah'); if (description) { console.log(description.extract); // Wikipedia text console.log(description.wikiUrl); // Attribution link }
Generate and download a full-year .ics:
typescriptconst icsContent = generateICS(allEvents, 'ARE Observances 2026'); downloadICS(icsContent, 'ARE-Observances-2026.ics');
Filter by tradition:
typescriptconst jewishOnly = allEvents.filter(e => e.tradition === 'judaism'); const orthodoxOnly = allEvents.filter(e => e.denomination === 'orthodox');
A date-accuracy validation script ships with this skill:
bashnode .agents/skills/okhp3-tradition-observance-calendar/scripts/validate-easter.js
Validates Western and Orthodox Easter computation against 11 known-correct dates each (US Naval Observatory / Ecumenical Patriarchate). Exit 0 = clean. Run after any change to the Computus algorithm.
Built by Jamie Hill · OverKill Hill P³ Published at github.com/OKHP3 Part of the OKHP3/skillz Agent Skill library. MIT License -- free to use, fork, and adapt. A nod to the source is appreciated.
Other measured skills in the registry, with their headline benchmark lift.