This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend.
What I Built
Someone close to me finds it cumbersome to move a rotating shift roster into a calendar. ShiftCal takes their own shifts as text, uses local Gemma to read the dates and shift types, and prepares a calendar file after they check each row.
A night shift makes the problem concrete. 31์ผ ๋์ดํธ means a night shift on the 31st. With the example hours of 23:00โ07:00, an October shift ends on November 1. Typing the wrong end date would leave a misleading calendar entry. ShiftCal calculates that boundary in tested code and shows both dates for review.
The real-person need is confirmed. The schedules shown here are fictional, and I have not yet collected feedback from the recipient.
Demo
Open the interactive recorded demo.
Click Try a recorded example. The fourth row, 4์ผ ์ด๋ธ๋?, stays unresolved. Correct it to Evening only if the original roster confirms that shift, or remove it. Check each remaining row to enable the calendar export. Day-off rows stay visible but create no event.
The public page replays a saved response from an actual Gemma run; it does not host inference. To process new text, follow the local setup in the README. The app needs Python and Ollama, with no Python or JavaScript packages. It currently accepts text only and uses Korea Standard Time.
Code
Source, setup and tests on GitHub ยท MIT license.
How I Built It
Gemma (gemma4:12b-it-q4_K_M, through Ollama) extracts a day and a D/E/N/O shift code from each Korean or English input line. Each result remains beside its source. Missing or duplicated model rows are flagged; explicit uncertainty stays unresolved.
JavaScript handles dates, shift hours and iCalendar formatting. It rejects invalid dates, duplicate dates and overlapping shifts. Changing a row or its settings clears the relevant confirmation. Export stays blocked until the remaining rows are valid and checked. There is no automatic calendar sync.
The Python server listens on loopback, calls a fixed local Ollama address and rejects foreign origins and Host headers. It limits input size and handles one extraction at a time. It does not log or save roster text. Users are asked to leave out names, workplace details and other people's shifts.
Fifteen unit tests passed, including month and year boundaries, leap years, overnight overlaps, uncertainty and server access checks. Four synthetic fixtures also went through the actual model: three matched exactly, with 13 of 14 date/code pairs matching overall. In the remaining row, ์ฃผ๊ฐ had no date. Gemma left both fields unresolved instead of retaining the expected day-shift code. The row remained visible and could not be exported. These are small functional checks, not an accuracy benchmark.
Desktop and mobile layouts were checked, along with a fresh three-line extraction in the browser. Calendar-app import and recipient field testing remain unverified. Reimporting a file may create duplicates; the app recommends a separate calendar.
Why Does Open Innovation Matter?
An open-weight model makes local roster processing possible without sending each schedule to a hosted model service. Open source makes the boundary around that model visible: the prompt, schema, validation and export code are all in the repository. Someone adapting ShiftCal can change the shift hours or inspect a date calculation without depending on a private API.
The first model download needs an internet connection and disk space. Local inference still needs suitable hardware and electricity; the application has no per-request service charge.
Prize Categories
Best Use of Gemma. Gemma performs the Korean and English roster extraction in the local application. The public demo includes a recorded response from that same implementation.
AI disclosure: Codex generated and revised the implementation, tests and prose under my direction. I supplied and confirmed the real-person problem. Executed tests and model responses were checked; no interview, testimonial or field trial is claimed. This entry uses the Fully Autonomous development disclosure.

Top comments (0)