The problem
What problem does Time-slot generator solve?
Every booking system has a list of times a client can pick. Nobody types those times in one by one: they come from rules such as "every weekday from 9 to 5 in half-hour slots" or "a class on the first Monday of every month", minus whatever is already booked, closed or taken.
The list is the easy part. The hard part is what happens on the Sunday the clocks change, when the server runs in a different time zone from the shop, when a monthly rule meets a week that starts mid-month, or when two clients press "book" on the last seat in the same second. Get one of those wrong and a slot disappears for a day, shows an hour late, or is sold twice.
This skill gives your coding agent the slot engine, written by the engineers who build the one inside a booking platform: rules authored in local time and stored as exact instants, seats, bookings, blackouts, the host's busy time, shared resources and working hours taken out, one availability check for both the list and the booking, and the last seat counted again at the moment it is booked. You own the code, run it on Next.js on Vercel, with Supabase or Firestore, under your own accounts.
The module
What does the skill build?
An agent with this skill builds one module for a Next.js App Router app, on your stack. For Time-slot generator that module consists of:
- 1. Daily ranges
- 2. Nth-weekday-of-month rules
- 3. One-off and whole-day slots authored in local time and stored as UTC
- 4. Seats
- 5. Bookings
- 6. Blackouts
- 7. Host busy time
- 8. Shared resources and working hours subtracted
- 9. One availability map for listing and booking
- 10. Capacity re-checked inside the booking transaction
- 11. Slot IDs that stay stable for existing bookings
Provenance
Where do the rules come from?
This skill was written by the engineer who builds the slot engine of a booking platform, and audited against the earlier implementation of that engine. The templates hold the properties a slot engine has to hold: every weekday of a monthly rule appears in any viewport; local days survive both DST changes; limits count from the strategy, not the requested week; output is the same under any process time zone; nothing the listing hides can be booked by ID; and on ordinary windows the slot IDs are the ones existing bookings already hold. A 23-test suite run under four process time zones states each one, and `references/provenance.md` has the record.
This module is the slot engine of a booking platform, written down by the engineer who builds it: strategy storage, slot generation, availability and the booking path, audited against the earlier implementation and rebuilt as plain TypeScript served from Next.js route handlers, on Firestore or Supabase/Postgres. The earlier implementation was a long-running API server on a document database, and it had already been through one hardening pass: true-UTC storage with a read-time normalizer, local-calendar weekday and month bucketing, bounded listener caches, and a single generation per booking. The audit ran that engine against DST, far-from-UTC and viewport cases. On ordinary windows the templates produce the same slot IDs and instants as the earlier implementation, which the differential check in testing.md confirms.
The ledger separates what the audit changed, what was kept on purpose, and what has not run in production yet.
Fixed in the templates
- PERIODICITY dropped every weekday but the first when cut short Candidates were produced one weekday at a time, all Sundays of the month and then all Mondays, and generation returned at the first date past the cutoff. A one-week view returned only the Sunday. The same early exit fired on
end.dateTime, on the booking window and onslotsLimit, so it also reached the booking path. Shipped: each month's dates are merged and sorted before emitting (generators.md). - A local day was skipped on DST transitions Days were advanced by adding 24 hours to an instant. When "now" was late in the evening before a 23-hour day, the next step landed two local days later; on a 25-hour day the same date came up twice and inflated
slotsLimitcounts. Shipped: iteration overYYYY-MM-DDlocal dates. - DAY_RANGE slots were 24 hours on 23- and 25-hour days The day slot ended at start + 24h, that is at 01:00 or 23:00 local on transition days, leaving an hour uncovered or double-covered. Shipped: slots run to the next local midnight.
- Output depended on the server's time zone Local strings were parsed with
new Date('...T09:00')(process zone) and weekdays read withgetUTCDay()on a "zoned" Date (correct only in a UTC process). The earlier implementation ran in a UTC process, so it was latent; any other deployment or a developer laptop got different slots. Shipped: Intl-only helpers (timezones.md) and a suite run under four process zones. - slotsLimit and daysLimit counted from the viewport The count began at the viewport start, so "the first 10 slots" differed per requested week, and a slot shown in a later week was absent from the booking-path generation. Shipped: limits count from the strategy's first bookable slot.
Show 6 moreShow fewer
- The pinned strategy zone was never read Strategies stored their authoring
timeZone, but generation used the project's current zone, so changing it reinterpreted every strategy. Shipped:strategy.timeZone ?? service.timeZone. - External busy time was converted twice or with the wrong zone Blocks stored both a wall-clock field and a UTC field; generation converted the wall-clock field with the project zone. Events stored as true UTC were shifted by the project offset; events from a calendar in another zone were off by the difference. Shipped: blocks are UTC instants only (availability.md).
- Working hours compared clock strings "00:00" sorts before "17:00", so a slot ending at midnight passed 08:00 to 17:00 hours. Shipped: instants on the slot's local start date, with next-day closing.
- Working hours applied to the listing only The booking path looked IDs up in a map built without the working-hours filter, so a slot hidden from the listing could be booked by ID. Shipped: one
buildAvailabilityfor both paths. - Malformed time strings became midnight An unparseable
timeeither fell back to 00:00 or produced an invalid date and no slots, with no error either way. Shipped:strategy-time-invalidat write time. - A limit of zero produced one slot The limit was checked only after a slot had been yielded, so
slotsLimit: 0gave one slot while the documentation promised none; a storednulllikewise stopped the strategy after its first slot. Shipped:0yields nothing,nullmeans no cap.
- PERIODICITY dropped every weekday but the first when cut short Candidates were produced one weekday at a time, all Sundays of the month and then all Mondays, and generation returned at the first date past the cutoff. A one-week view returned only the Sunday. The same early exit fired on
Non-negotiables
What are the 5 rules the module never breaks?
Every module built from this skill holds these, whoever builds it. The same list is in the skill's README and SKILL.md, so the agent reads it before it writes a line.
Never change the slot ID input.
md5("<utcStartISO>;<duration>;<strategyId>")is the identity every client and every booking holds; a different input orphans them all. A test pins the format.Never infer "overnight" from end before start.
A reversed range is far more often a typo than a night shift, so an overnight window needs
overnight: true. The validation test refuses 17:00 to 09:00 and accepts the explicit overnight window.Never generate without a horizon.
maxHorizonDaysandmaxSlotscap every strategy, since one with no end would otherwise generate until 2038. A test stops a strategy at a 10-day horizon, then atmaxSlots, and expectstruncatedonly in the second case.Never filter availability in the listing only.
The listing and the booking path read one
buildAvailabilitymap, so an ID cannot book what the listing hides. Both entry points inservice.tscall the samecomputeAvailability, and a test resolves booking IDs against that map.Never count a host's booking of this service as host busy time.
It already subtracts seats as a
BOOKING; blocking on it as well hides a slot that still has room. Both stores exclude the service from the host query, andSlotStore.listBusystates the rule.
Fit
When should you use it, and when not?
Use it for
- Generating bookable slots from rules: "Monday to Friday 09:00 to 17:00 every 30 min", "first and last Friday of each month 18:00 to 20:00", "whole days, weekends only", "this one Saturday 10:00 to 14:00".
- Showing availability: capacity per slot, minus bookings, blackouts, a host's other commitments, shared rooms or equipment, and outside working hours.
- Booking slots by ID with a capacity re-check that holds under concurrent requests.
- Fixing slot code with time-zone bugs, or moving one off wall-clock-as-UTC storage.
Not for
- Booking screens, a walk-up terminalInstead
booking-kiosk - Public scheduling links per host, calendar sync, e-mail invitesInstead
calendar-scheduling-links - Ticketed events on one date, deposits, no-show holdsInstead
bookable-events - Invoices for bookingsInstead
invoicing - Calendar recurrence (RRULE, iCalendar event series)Instead
rruleor the calendar provider's API
Build it yourself
How do I install it?
One command. The skills.sh CLI installs the skill into every skills-compatible agent it finds.
$ npx skills add timerise-ai/time-slot-generatorClaude Code
Invoke with /time-slot-generator
Codex CLI
Invoke with $time-slot-generator
Gemini CLI
Invoke with /skills
Name the agents instead with -a, for example npx skills add timerise-ai/time-slot-generator -a claude-code -a codex. Or clone the repository into your agent's skills folder. Nothing in it is agent-specific.
What is inside the repository (13 entries)
SKILL.mdEntry point: trigger, architecture, adaptation contract, critical facts, hard rules, quick start, reference directoryreferences/adaptation.mdHost prerequisites, seam contract, rename table, integration points, order of work, the non-negotiablesreferences/strategy-model.mdStrategy types, bounds, limits, types, validationreferences/timezones.mdUTC and wall clock, the DST policy, Intl helpers, the legacy normalizerreferences/generators.mdThe engine, slot identity, horizon, costreferences/availability.mdBookings, blocks, resources, working hours, the service entry point, the booking pathreferences/supabase-backend.mdSchema, RLS, the store,book_slotsreferences/firestore-backend.mdCollections, indexes, the store, the transaction capacity checkreferences/nextjs-routes.mdThe server client, the listing and booking route handlers, error codes, environmentreferences/testing.mdThe suite, running it under four time zones, the differential checkreferences/provenance.mdThe audit ledger: fixed, kept deliberately, designed hereevals/prompts.mdwith what an operator types, and one file per agent eval run.github/workflows/agent-eval.ymlRuns the agent evals on every published release
Recent releases
- v0.1.3October 16, 2026
From scoring the prompt-1 agent eval runs against 0.1.2. No template changed.
- v0.1.2October 16, 2026
Fix release, from scoring the dispatched prompt-1 agent eval runs against 0.1.1.
- v0.1.1October 16, 2026
Security fix release, from scoring the prompt-1 agent eval runs against 0.1.0.
After installing
What do I tell my agent?
Say what you need in your own words; the skill supplies the how. These are starting points, and the ones we tested say how it went.
Our studio books classes and private sessions from weekly opening hours, like weekdays 9 to 5 every 30 minutes and the first Saturday of each month. Add an API to this Next.js app on Supabase that lists the free times for a service and books one, without overbooking when two people take the last spot.
Our booking times are an hour off after the clock change, and the week view sometimes only shows Monday. Fix how this app generates its time slots so it is right in every time zone our customers are in.
FirestoreAudit our availability code: customers can book times that the calendar does not show, and staff who are busy with another service still appear free.
Tested
How does it do in each agent?
We install the skill into an empty Next.js app, give the agent one of the prompts above and no further help, then type-check, build and run the tests it left behind. Nothing is fixed by hand before the checks, and a failing run is published like a passing one. The procedure and every result are public, and the first prompt runs again before each release.
- Built, checks pass
Gemini CLI0.64.0
gemini-3.8-flash
Our studio books classes and private sessions from weekly opening hours, like weekdays 9 to 5 every 30 minutes and the first Saturday of each month. Add an API to this Next.js app on Supabase that lists the free times for a service and books one, without overbooking when two people take the last spot.
Typecheck: passBuild: passTests: pass- Time
- 3 min
- Changed
- 19 files, +3,384 lines
- Stack
- Supabase
- Skill
- v0.1.3
- Run
- Oct 16, 2026
What we saw
Rubric 8/8, scored from the final summary and the tool counts. It ran the copy command: two
write_filecalls and 120 lines written by its own tools, against 17 calls and over 2000 lines in the earlier runs. The handover is complete and the 23 shipped tests are counted apart from three inlib/slots/studio.test.ts. It still names the guard at line 29 of a route the command wrote with the guard at line 31, so its line numbers are its own count and were weaker evidence of drift in the earlier runs than those notes assumed. - Built, checks pass
Codex CLIcodex-cli 0.163.0
gpt-6.1-sol
Our studio books classes and private sessions from weekly opening hours, like weekdays 9 to 5 every 30 minutes and the first Saturday of each month. Add an API to this Next.js app on Supabase that lists the free times for a service and books one, without overbooking when two people take the last spot.
Typecheck: passBuild: passTests: pass- Time
- 2 min
- Changed
- 21 files, +3,370 lines
- Stack
- Supabase
- Skill
- v0.1.3
- Run
- Oct 16, 2026
What we saw
Rubric 8/8, scored from the transcript. It ran the quick start's copy command, then changed only the suite's
node:testimport and thetestscript; its finalgit statusshows no other change to a template. Three tests of its own sit inlib/slots/service.test.ts, and the handover names the schema, both variables and the guard atroute.ts:31. - Built, checks pass
Claude Code2.1.301
claude-opus-5-5
Our studio books classes and private sessions from weekly opening hours, like weekdays 9 to 5 every 30 minutes and the first Saturday of each month. Add an API to this Next.js app on Supabase that lists the free times for a service and books one, without overbooking when two people take the last spot.
Typecheck: passBuild: passTests: pass- Time
- 2 min
- Changed
- 20 files, +3,356 lines
- Stack
- Supabase
- Skill
- v0.1.3
- Run
- Oct 16, 2026
What we saw
Rubric 8/8, scored from the final summary.
book_slotsis left as shipped, both packages come from npm, the 23 shipped tests are reported apart from three of its own inlib/slots/studio.test.ts, and the handover namessupabase/schema.sql, both server-only variables and the guard atapp/api/bookings/route.ts:31.
Build it with Timerise
How long does it take, and what does it cost?
We quote this module per project. The price depends on what it has to connect to. The path to a number is short and free:
Step 1
Brief
Tell us what the module must connect to. Takes minutes, in a chat.
Step 2
Prototype in 48 hours
A clickable prototype of your system and a quote, at no cost.
Step 3
Build and handoff
One project price. Source code, documentation and IP are yours.
Two ways to get Time-slot generator
Build it yourself
Install the skill. Your own agent builds the module.
- MIT licensed, no strings
- Runs in Claude Code, Codex CLI and Gemini CLI
- The same rules our engineers build by
$ npx skills add timerise-ai/time-slot-generatorBuild it with Timerise
Send a brief. We build Time-slot generator into a system you own.
- Clickable prototype and a quote within 48 hours, free
- One project price, no subscription, no commission
- Source code, documentation and IP handed over
Generated from the skill's own files at commit bb2cc36. Every rule above links to where the repository says it. All skills