Turn a photo of your work shift schedule into calendar events.
A Claude Code plugin for everyone who gets their work roster as a photo on their phone and then types it into a calendar by hand.
Hand Claude the picture. It reads the schedule, shows you the shifts it found, waits for
you to confirm, and writes a standard .ics you can open in any calendar app.
/shifts # with the roster photo attached
Shift schedules arrive as a photo of a printout pinned to a wall. Every month the same half hour goes into copying dates and times into a calendar — and a single misread digit means showing up on the wrong day.
This does the transcription, but deliberately stops and shows you the table before writing anything. You confirm; it builds the file.
/plugin marketplace add PascalKremp/shift-slurp
/plugin install shift-slurp
python3 (3.9 or newer). That's it — the ICS builder is pure standard library. No venv,
no pip install, no API keys, no account anywhere.
- Timed shifts, including odd formats —
13:30,8.00,0800all parse - Overnight/night shifts — an end time at or before the start rolls to the next day
- All-day entries — vacation, sick days, time off, as one multi-day block
- Split shifts, training blocks, breaks — as titles and descriptions
- DST correctly — times convert from a real IANA timezone per date, so a roster that spans the clock change still lands right
- Re-imports — event UIDs are derived from the shift itself, so importing a corrected roster updates events instead of duplicating them
Optionally, if you have a calendar tool connected (an MCP server, say), it can also create the events directly — de-duplicating against what's already on the calendar, and never overwriting or deleting an existing event.
The skill is orchestration around one script you can also run yourself:
python3 skills/shift-slurp/scripts/build_ics.py --input shifts.json --out shifts.icsshifts.json:
{
"calendar_name": "Work shifts",
"timezone": "Europe/Berlin",
"default_title": "Shift",
"default_location": "Store Nord",
"shifts": [
{"date": "2026-09-01", "start": "13:30", "end": "19:30"},
{"date": "2026-09-03", "start": "22:00", "end": "06:00", "title": "Night shift"},
{"date": "2026-09-10", "all_day": true, "title": "Vacation", "end_date": "2026-09-14"}
]
}date is required; timed shifts need start + end; day events use "all_day": true
with an inclusive end_date. title, location and description are per-shift and
fall back to the default_* keys. Pass --input - to read the JSON from stdin.
The last line of stdout is a JSON summary — event counts, date range, and warnings for overnight rollovers and duplicate rows — so it drops into a pipeline cleanly. Everything else goes to stderr.
Output is RFC 5545: CRLF line endings, 75-octet line folding, proper escaping, UTC instants converted from your timezone.
MIT