.cursor/skills/add-calendar-system/SKILL.md
Step-by-step workflow for adding a new calendar or timekeeping system to the Library of Time, including creating the Docs entry, regenerating nodeData, wiring the main function into the CalendarAPI layer and nodeUpdate.js, and adding tests. Use when introducing a new calendar node to the site.
npx skillsauth add CodapopKSP/LibraryOfTime add-calendar-systemInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill whenever you want to:
CalendarAPI/Timekeeping).This workflow assumes you also follow:
calendar-math – for deriving algorithms and conversions.calendar-conventions – for date/epoch/timezone conventions and utilities.js helpers.For each new system, follow this pipeline:
Content/nodeData.js → 3. Implement main function → 4. Wire into nodeUpdate.js → 5. Add tests.Each step below is required unless explicitly skipped by the user.
Docs/src/ that matches the system:
Docs/src/SolarCalendars/Docs/src/LunarCalendars/Docs/src/LunisolarCalendars/Docs/src/SolilunarCalendars/Docs/src/ProposedCalendars/Docs/src/OtherCalendars/, Docs/src/OtherTime/, etc.Docs/ rule).Docs/src/SUMMARY.md under the right section, so buildNodeData.js will include it.#### Info (months, weekdays, alignment)When adding month names, weekday names, or similar reference material:
buildNodeData.js table conversion).#### Overview, #### Accuracy, and #### Source as To be determined. (or equivalent stubs) and put only tables under #### Info.Content/nodeData.jsContent/nodeData.js and the mdBook output, typically via:
bash build.shnode buildNodeData.js if only Content/nodeData.js is needed.Content/nodeData.js by hand; it is generated.Content/nodeData.js:
egyptian-civil-node) that will be passed to setTimeValue in nodeUpdate.js.CalendarAPI/ based on category:
CalendarAPI/Calendars/solarCalendars.jsCalendarAPI/Calendars/lunarCalendars.jsCalendarAPI/Calendars/lunisolarCalendars.jsCalendarAPI/Calendars/otherCalendars.jsCalendarAPI/Calendars/solilunarCalendars.jsCalendarAPI/Calendars/proposedCalendars.jsCalendarAPI/Timekeeping/*CalendarAPI/Other/*getXxxDate(currentDateTime, timezoneOffset)getXxxCalendar(currentDateTime)createAdjustedDateTime, getMoonPhase, or other module APIs at top level — script load order may make them undefined. See calendar-conventions (Structure: main function and load-time safety)."Calendar Name" or "TODO: implement Xxx calendar".nodeUpdate.js without further shape changes."TODO: implement …"), treat that request as explicit permission to change the function’s behavior.calendar-math and calendar-conventions (anchor dates, timezone handling, helpers, etc.) for the real implementation.output and in return-object fields (year, month, etc.) that the user or docs specified. If no calendar year label was requested, keep year: null and do not append a year to the main display string.nodeUpdate.jsnodeUpdate.js and identify the correct wrapper function:
updateSolarCalendars(currentDateTime, timezoneOffset)updateLunisolarCalendars(currentDateTime) or lunar-specific wrapper.updateOtherCalendars(currentDateTime)updateProposedCalendars(currentDateTime, timezoneOffset)updatePopCultureCalendars(currentDateTime, timezoneOffset)updateClocks_Fast or updateClocks_Slow depending on update frequency.setTimeValue call within the appropriate wrapper:
Content/nodeData.js (e.g., 'solar-hijri-node').getSolarHijriDate(currentDateTime, springEquinox)).springEquinox) instead of recomputing.The main grid and nodeUpdate.js are not enough for the Calendar View side panel: it maintains its own map of node id → getter. If you skip this step, selecting the new system in Calendar View shows no per-day output and no month-based cell shading, because getNodeValueForDay looks up getters[nodeId] and gets undefined.
UserInterface/calendarView.js and find buildNodeValueGetters.id from Content/nodeData.js (e.g. 'mandaean', 'saka-samvat'). This is the short id without the -node suffix used in setTimeValue.Date passed in (same pattern as neighbors), for example:
'mandaean': function (dt) { return typeof getMandaeanDate === 'function' ? getMandaeanDate(dt) : ''; }(dt) only; some use (dt, offset)—mirror an existing calendar in the same API file if unsure.getNodeValueForDay builds monthKey from raw.month and raw.year when the getter returns an object with month != null. If your calendar returns month: null for intercalary or special days, those cells may not get a tint (same as other systems).Tests/:
Tests/solarCalendarTests.jsTests/lunisolarCalendarTests.jsTests/lunarCalendarTests.jsTests/otherCalendarsTests.jsTests/proposedCalendarTests.jsTests/computingTimeTests.jstestXxxCalendar() using helpers like runSolarTests, runCalendarEquinoxTests, or category-specific runners.Tests/runCalendarDevTests.js, add your new test function to the testFunctions array so it can be run in isolation via runCalendarDevTests().testFunctions array in runSolarCalendarTests) once you are ready to make it part of the full suite.runAllTests() commented out in Tests/runTests.js unless the user explicitly wants to run tests continuously.Before considering a new calendar/time system “hooked up”, confirm:
Docs/src/... with title/outline and is referenced from Docs/src/SUMMARY.md.Content/nodeData.js has been regenerated (via build.sh or buildNodeData.js), and the node id is known.CalendarAPI/... file, following existing patterns and conventions.nodeUpdate.js calls setTimeValue for this node id using the main function.calendarView.js: buildNodeValueGetters includes an entry for the node’s short id (so Calendar View cells and month shading work when that system is selected).Tests/*.js file and are wired into that file’s runner.development
Compute weekdays correctly for calendars where some days (intercalary/epagomenal) are excluded from the weekday cycle. Use when implementing or debugging weekday logic with “skipped days”, “epagomenal”, “intercalary”, or “non-weekday” days.
development
Catalogs common implementation patterns used by existing calendars and timekeeping systems in the Library of Time, with examples and guidance on when to use each pattern. Use when choosing how to structure a new calendar’s algorithm.
tools
Use user-provided month names or labels in calendar implementations and output. Use when implementing or updating a calendar and the user has given a list of month names (including for leap months), so the implementation does not default to numeric-only output.
development
Designs and implements complete calendar and timekeeping calculation modules for the Library of Time project, including algorithms, date conversions, and tests. Use when working on calendar logic, adding a new calendar, or one-shotting an entire calendar implementation from a prompt. Treat `CalendarAPI/Calendars/*`, `CalendarAPI/Timekeeping/*`, and `CalendarAPI/Other/*` as a single Calendar API layer.