Install
$ agentstack add skill-okhp3-skillz-okhp3-tradition-observance-calendar ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
okhp3-tradition-observance-calendar
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.
Execution contract
- Accept a target year and optional tradition or denomination filter. Validate
the year before constructing provider URLs or date objects.
- Normalize every source into
ObservanceEventand retain the source,
attribution, and caveat fields. Computed dates, provider dates, and missing dates must remain distinguishable.
- Use
Promise.allSettledfor independent provider or month requests so one
outage does not discard successful results. Surface partial failure in the UI or return metadata rather than hiding it.
- Do not replace the deterministic Christian Computus path with a paid,
credentialed, or unverified holiday API. Run the bundled Easter validator after algorithm changes.
- Treat Islamic dates as calendar estimates. State the local moon-sighting
caveat, and never present an estimated date as universally authoritative.
- Fetch Wikipedia descriptions lazily, cache only non-sensitive results, and
display the exact attribution string with the returned article URL.
- Escape user- or provider-derived values before inserting them into
.ics.
Follow the bundled RFC 5545 line-folding and date rules.
Bundled reference files
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.
1. Scope Rules
A holiday is in scope if and only if it meets both criteria:
- Abrahamic lineage -- traces its roots to the Abrahamic covenant
- US population threshold -- practiced by a tradition representing ≥1% of the US population per Pew Research Center
| 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/
2. Unified Event Type
All holiday sources normalize to this shared interface:
interface 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)
}
3. Emoji Registry
export 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.
4. Jewish Holidays -- Hebcal REST API
No API key. CC BY 4.0. Free.
4.1 Endpoint
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=50
Parameters 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)
4.2 Fetch pattern
async function fetchJewishHolidays(year: number): Promise {
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;
}
4.3 Response item shape
{
"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"
}
4.4 Normalization rules
- Strip Hebrew year suffix from title for display:
"Rosh Hashana 5787"→"Rosh Hashana" - Detect multi-day events by grouping items with matching normalized base name across consecutive dates
- Set
endDateto the last consecutive day with the same name;isMultiDay = truewhen span > 1 - Populate
hebrewNamefromhebrewfield - Populate
sourceUrlfromlinkfield - Populate
wikiArticlefromWIKIPEDIA_ARTICLE_MAP[normalizedName](see Section 5) - Set
emoji = '✡️',tradition = 'judaism',denomination = 'all'
4.5 Attribution
Display in UI: "Calendar data via Hebcal.com (CC BY 4.0)" Link: https://www.hebcal.com
5. Islamic Holidays -- AlAdhan REST API
No API key. Free. GPL-3.0.
5.1 Strategy
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.
5.2 Endpoint (per month)
GET https://api.aladhan.com/v1/gToHCalendar/{month}/{year}
5.3 Fetch pattern
> 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.
async function fetchIslamicHolidays(year: number): Promise {
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;
}
5.4 Response day shape (relevant fields)
{
"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"]
}
}
5.5 Allowed holiday filter (US mainstream Sunni/general Islamic)
Only include days where at least one entry in holidays[] matches this allowed set:
const ALADHAN_ALLOWED: Set = 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.
5.6 Display name normalization
const ALADHAN_DISPLAY_NAMES: Record = {
"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",
};
5.7 Multi-day detection
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.
5.8 Moon sighting caveat
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."
5.9 Attribution
Display in UI: "Islamic calendar data via AlAdhan.com" Link: https://aladhan.com
6. Christian Holidays -- TypeScript Algorithm
No external API. Fully client-side. Zero dependencies.
6.1 Western Easter (Gregorian Computus)
function 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
6.2 Orthodox Easter (Julian Computus + Gregorian offset)
function 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
6.3 Holiday generation
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.
7. Event Description -- Wikipedia REST API
No API key. Free. CC BY-SA 3.0. No external cost.
7.1 Endpoint
GET https://en.wikipedia.org/api/rest_v1/page/summary/{article_title}
7.2 Fetch pattern
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.
7.4 Attribution
Always display in UI: "Description via Wikipedia (CC BY-SA 3.0)" with link to the Wikipedia article URL returned by the API.
8. iCalendar (.ics) Generation
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.
9. Session Caching Strategy
| 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.
10. Attribution Requirements
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)" |
11. Validation Reference
| 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 |
12. Usage Examples
Fetch all observances for 2026:
const [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:
const 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:
const icsContent = generateICS(allEvents, 'ARE Observances 2026');
downloadICS(icsContent, 'ARE-Observances-2026.ics');
Filter by tradition:
const jewishOnly = allEvents.filter(e => e.tradition === 'judaism');
const orthodoxOnly = allEvents.filter(e => e.denomination === 'orthodox');
Validation script
A date-accuracy validation script ships with this skill:
node .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.
About
Built by Jamie Hill · OverKill Hill P³ Published at
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: OKHP3
- Source: OKHP3/skillz
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.