GrepBoard/Manuals
84 manuals ·

Find a common meeting time from five busy lists, then check it

·updated ·claude-sonnet-5-5 · Python 3.13 · run 2026-10-20·4 steps

Paste five people's busy times in five formats, get every 60-minute slot they all share as a table, and compare it with a short Python interval check.

Five replies, five formats: "Mon 9-10:30am", "Tue all morning", "Thu out of office all day", and one person writing in a time zone three hours behind everyone else. Finding one hour nobody is busy means drawing a grid first.

busy.en.txt
[A] Mon 9-10:30am / Tue 1pm-3pm / Wed 11:00-12:00 / Thu 2:00-4:00 pm / Fri until 11am[B] Monday lunch hour (12-1pm), Tue all morning, Wed after 2pm (back-to-back till close), Thu 10:00-11:30, Fri 13:00-14:30[C] Mon 14:00-16:00 | Tue 10am to 11am | Wed 9-10 | Thu out of office all day | Fri 3pm-4pm[D] Mon 10:30-12:00, Tue from 3:30pm to the end of the day, Wed 12-1 (lunch), Thu 4-5pm, Fri all morning[E] (local time, 3 hours behind UTC) Mon 06:00-08:00, Tue 07:00-09:00, Wed 09:00-11:00, Thu 06:30-08:00, Fri 08:00-10:00

The week is Mon 2026-10-12 to Fri 2026-10-16, working hours are 09:00–17:00 UTC, the meeting is 60 minutes. Names and times are made up.

A short prompt

The plain version: "find a 1-hour time that works for everyone", plus the dates. Two runs on claude-sonnet-5-5 both recommended Monday 13:00–14:00, which is a correct slot. The trouble is what surrounds it.

  • Run 1 named only two of the five valid slots (Monday 13:00 and a Monday 16:00 backup). Run 2 listed all five in a table. With the same input, how much you get back changes between runs.
  • Both spelled out assumptions the input never made: that A–D share one time zone (UTC, in run 2), and that the working day is 9:00–17:00.
  • Run 2 added that today is 2026-10-20, so that week has already passed, and asked for new dates. The input never mentioned today's date.
  • Neither gave a table a script can read. Run 2's table has the slots but no per-person columns.

Pin down the rules and the output

Anthropic's prompting guide says to state the output format and constraints explicitly. A chat model cannot see a real calendar, so every assumption you leave out gets filled in for you. Put working hours, time zone, what "all morning" means, the step between candidates and the table columns in the rules.

[1] The prompt file. Change the dates, working hours, meeting length and E's offset to fit your case. The busy lists go inside the final <busy> tag.

head.en.txt
Find 60-minute meeting slots that all five people (A–E) can attend. The busy lists inside <busy> are what each person sent, in their own format. Rules:- Dates: Monday 2026-10-12 to Friday 2026-10-16. Use UTC for everything you output.- Working hours are 09:00–17:00 UTC. The whole meeting must fit inside them.- Person E wrote times in their local time (UTC minus 3 hours). Convert to UTC before comparing.- Read phrases like "all morning" as 09:00–12:00, "all day" as 09:00–17:00, "until close" as 17:00, and "until 11am" as starting at 09:00.- Candidate start times are every 30 minutes (09:00, 09:30, ...). A meeting may not overlap any busy time at all; touching at the boundary is fine.- Step 1: output a Markdown table of every candidate that works for all five, with exactly these columns: Date | Start | End | A | B | C | D | E. Put "free" in the person columns.- Step 2: below the table, one line "Total: N candidates".- If there are none, output exactly: None- No other text. <busy>

"Touching at the boundary is fine" keeps a meeting at 12:00 from counting as an overlap with one that ends at 12:00.

[2] Run it. --tools "" turns off built-in tools, --strict-mcp-config drops connected MCP tools, and --setting-sources "" skips your settings and CLAUDE.md files, and the prompt goes in on standard input.

console
$ (cat head.en.txt busy.en.txt; echo "</busy>") > prompt.en.txt$ claude -p --model claude-sonnet-5-5 --max-turns 1 --tools "" --setting-sources "" --strict-mcp-config < prompt.en.txt > out.en.1.txt$ cat out.en.1.txt| Date | Start | End | A | B | C | D | E ||---|---|---|---|---|---|---|---|| 2026-10-12 | 13:00 | 14:00 | free | free | free | free | free || 2026-10-12 | 16:00 | 17:00 | free | free | free | free | free || 2026-10-13 | 12:00 | 13:00 | free | free | free | free | free || 2026-10-14 | 10:00 | 11:00 | free | free | free | free | free || 2026-10-16 | 16:00 | 17:00 | free | free | free | free | free | Total: 5 candidates

A second run returned the same table.

[3] Copy the same busy times into JSON. Each person is [offset in minutes, [items]], each item is "day start-end". Only E gets an offset (180), which moves their times into UTC.

busy.en.json
{"work": ["09:00", "17:00"], "minutes": 60, "days": [12, 13, 14, 15, 16], "month": "2026-10", "people": {  "A": [0, ["12 09:00-10:30", "13 13:00-15:00", "14 11:00-12:00", "15 14:00-16:00", "16 09:00-11:00"]],  "B": [0, ["12 12:00-13:00", "13 09:00-12:00", "14 14:00-17:00", "15 10:00-11:30", "16 13:00-14:30"]],  "C": [0, ["12 14:00-16:00", "13 10:00-11:00", "14 09:00-10:00", "15 09:00-17:00", "16 15:00-16:00"]],  "D": [0, ["12 10:30-12:00", "13 15:30-17:00", "14 12:00-13:00", "15 16:00-17:00", "16 09:00-12:00"]],  "E": [180, ["12 06:00-08:00", "13 07:00-09:00", "14 09:00-11:00", "15 06:30-08:00", "16 08:00-10:00"]]}}

[4] The script computes the slots with an interval-overlap test and compares them with the first three columns of the AI's table. Intervals [s,e) and [a,b) overlap when s < b and a < e; an end equal to a start does not count.

check.py
#!/usr/bin/env python3"""usage: check.py busy.json out.txt  — compute the slots, then compare with the AI's table"""import json, syscfg = json.load(open(sys.argv[1], encoding="utf-8"))def t(s): h, m = s.split(":"); return int(h) * 60 + int(m)spans = {d: [] for d in cfg["days"]}               # day -> busy spans in organizer timefor shift, items in cfg["people"].values():        # shift = minutes to add to this person's times    for it in items:        d, rng = it.split(); a, b = rng.split("-")        spans[int(d)].append((t(a) + shift, t(b) + shift))want = set()for d in cfg["days"]:    for s in range(t(cfg["work"][0]), t(cfg["work"][1]) - cfg["minutes"] + 1, 30):        e = s + cfg["minutes"]        if all(not (s < b and a < e) for a, b in spans[d]):   # no overlap with any busy span            want.add((f"{cfg['month']}-{d}", f"{s//60:02d}:{s%60:02d}", f"{e//60:02d}:{e%60:02d}"))rows = [[c.strip() for c in l.strip().strip("|").split("|")]        for l in open(sys.argv[2], encoding="utf-8") if l.startswith("|")]got = {tuple(r[:3]) for r in rows if r[0][:2] == "20"}        # skip header and separator rowsfor x in sorted(want - got): print("MISSING", *x)for x in sorted(got - want): print("EXTRA  ", *x)print(f"script {len(want)}, AI {len(got)}, missing {len(want-got)}, extra {len(got-want)}")sys.exit(1 if want != got else 0)
console
$ python3 -I check.py busy.en.json out.en.1.txt; echo "exit $?"script 5, AI 5, missing 0, extra 0exit 0

To see a failure, out-bad.en.txt was made from out.en.1.txt by deleting the Tuesday 12:00 row and adding a Friday 15:30 row by hand (the model did not make this error).

console
$ python3 -I check.py busy.en.json out-bad.en.txt; echo "exit $?"MISSING 2026-10-13 12:00 13:00EXTRA   2026-10-16 15:30 16:30script 5, AI 5, missing 1, extra 1exit 1

Feed the script the answer to the short prompt and all five slots come back MISSING, because there is no table to read. That is why the format is part of the prompt.

Where it can go wrong

  • Writing the JSON is manual work. If you enter "all morning" as 09:00–12:00 it has to match what the prompt says, otherwise the two disagree because of interpretation, not because the AI erred.
  • The model never got the time zone wrong in these runs. But without the "UTC minus 3 hours" line there would be no way to check, and the prompt was not run without it.
  • The script compares sets of start times only. It does not look at the free cells.

If calendars can be shared, the scheduling feature of your calendar app is more reliable. This method fits when you only have busy times from email or chat. Confirm the chosen time with the attendees once more.

#meeting-time#scheduling#claude#prompt