Inspiration

The dangerous prescriptions are not the complicated ones. They are four ordinary ones.

Levothyroxine says "on an empty stomach, one hour before food." Calcium says "with a meal" and, separately, "at least four hours from levothyroxine." An antibiotic says "every six hours." A stomach protectant says "one hour before or two hours after everything else." Each instruction is clear. Each was explained properly. Nobody ever checks whether they can all be true on the same Tuesday.

They frequently cannot. And the way people discover this is standing in the kitchen at six in the evening realising the thyroid tablet has nowhere left to go — at which point the usual outcome is to take it anyway, at the wrong time, and not mention it.

This is a scheduling problem wearing a medical costume. So we treated it as one.

What it does

It compiles confirmed medication directions into formal temporal constraints and decides, provably, whether the day is schedulable.

  • If it is, you get a concrete schedule laid out on a 24-hour ring alongside your sleep, meals and school or work blocks, with the safety margins shown.
  • If it is not, you get the minimal set of requirements that makes it impossible, in plain language — and the app proves minimality by re-solving with each one of them removed.

It never invents, changes, or recommends a dose. The output of an impossible regimen is not a workaround. It is a precise, specific question to take to a pharmacist: these seven requirements cannot all hold, here is why, which one is flexible?

How we built it

A real finite-domain constraint solver, written from scratch.

The day is 288 five-minute slots. Each dose is a variable; its domain is the slots that instruction permits. The constraint language covers frequency (n times daily, every N hours, at bedtime, on waking), same-drug separation, pairwise drug-drug spacing, food relations (with food, empty stomach before or after a meal), waking-window and lying-down anchors, avoid-blocks for school and work, and daily-maximum ceilings.

Solving is AC-3 arc consistency propagation followed by backtracking search with conflict-directed backjumping, then a second objective pass that maximises the tightest spacing margin without moving any dose outside its instructions.

When the problem is unsatisfiable, a deletion-based MUS extraction finds a minimal core, and every core is then independently verified: remove any single member and the instance must become satisfiable.

Every constraint carries provenance back to the exact instruction text that produced it, visible in the UI. Everything runs in the browser and persists to IndexedDB. There is no network call, no account, and no data leaves the device.

Challenges we ran into

Two things were harder than expected.

The first was making unsatisfiability useful. "No solution" is worthless to a patient. A minimal core is a sentence a pharmacist can act on, but only if it is genuinely minimal — a core with one irrelevant constraint in it sends someone to ask the wrong question. That is why minimality is verified rather than assumed.

The second was resisting helpfulness. Early versions wanted to suggest moving a dose "just thirty minutes." That is prescribing, and it is exactly the line this tool must not cross. What replaced it is the school-day-shifted example: change the person's day, not the prescription.

Accomplishments we're proud of

Five shipped examples, every number measured at runtime:

example result propagations backtracks time
thyroid-morning satisfiable 850 24 6.9 ms
school-day-collision unsatisfiable 46 0 1.2 ms
school-day-shifted satisfiable 1,254 28 22.0 ms
overnight-antibiotic satisfiable 1,451 17 28.2 ms
sucralfate-day satisfiable 53,618 12,472 121.6 ms
  • school-day-collision returns a minimal core of 7 requirements, extracted in 40.9 ms, with minimality verified: removing any single member makes the day schedulable.
  • school-day-shifted is the same four prescriptions with dinner moved from 18:30 to 17:30. It solves. That pair is the clearest argument the project makes.
  • sucralfate-day is the case arc consistency cannot settle — five pairwise spacing rules all routed through one tablet with nothing anchored to a meal — and it needs the full search: 53,618 propagations and 12,472 backtracks.

Honest limits

This is not medical advice and it does not diagnose anything. It schedules only what the user confirms they were already told. It has no drug database, so it does not know about interactions you did not enter, and it will happily schedule a regimen that is clinically wrong but temporally consistent. A pharmacist is still the authority on the content of the constraints; this tool only reasons about their timing.

The example regimens are realistic but constructed by us, not drawn from real prescriptions. Constraints are entered through a builder rather than parsed from free-text label wording, which is the obvious next thing and also the obvious place to introduce errors.

Five-minute resolution means it cannot express a "take at 8:02" requirement, which is fine for oral medication and would not be for infusion.

What we learned

Formalising the directions was more revealing than solving them. Writing "on an empty stomach" as no meal in the preceding 60 minutes and none in the following 30 forces a precision that ordinary pharmacy language deliberately avoids — and a large part of the value here is simply that the ambiguity becomes visible before it becomes a missed dose.

What's next

Parse constraints directly from label text with a confirmation step, add a real interaction database as a separate advisory layer, support multi-day regimens (alternate-day dosing, tapers), and produce a printable one-page schedule and a pharmacist-facing conflict sheet.

Built With

  • ac-3
  • canvas
  • constraint-programming
  • csp
  • digital-health
  • indexeddb
  • javascript
  • local-first
  • medication-safety
  • sat-solver
Share this project:

Updates