This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
The appointment moved. Alex saw the message. Maya saw the request for a ride, but her work shift overlapped. Someone still needed to bring their relative home.
Everyone wanted to help. The chat contained the details. What it did not contain was one reliable answer to a small question: who had actually agreed to do what?
I built CareRelay, a local family coordination assistant that turns scattered messages into an evidence-linked plan. It uses Ministral 3 14B through Ollama to suggest appointments, transport, errands, pickups and confirmation tasks. A person reviews the source and approves each suggestion. The caregiver then explicitly accepts the responsibility.
CareRelay also includes Never-Lost Care Handoffs, its durable reminder feature powered by Temporal. A reminder starts only for an accepted responsibility with a valid reminder time. Its timer survives worker shutdown, and its eventual in-app delivery still checks whether the responsibility and acceptance are current.
Alex, Maya, Sam and Robin are fictional caregivers in the synthetic demonstration. CareRelay is organizational software, with no diagnosis, dosing or treatment guidance. The burden it addresses is the repetitive work around helping: reconstructing conversations, checking dates, chasing unanswered requests and remembering the same responsibility again.
Demo
Watch the CareRelay demonstration on YouTube.
The 94-second demonstration uses actual local model inference and explicitly synthetic family messages. It follows the source into human review, shows Alex accepting the clinic responsibility, and schedules a clearly labelled real 20-second reminder timer.
The recording script stops its own worker. Temporal records the timer firing while that worker is offline. After the worker restarts, one reminder appears inside CareRelay. The caregiver snoozes it, then a reviewed appointment change cancels the obsolete reminder. The replacement needs fresh acceptance. The return ride remains unassigned throughout.
The short timer is accelerated demonstration timing. No days are claimed to have passed. The recording, process-control script and verification reports preserve what actually happened. The 1920x1080 export uses genuine Kokoro-82M narration with the am_fenrir voice and an English subtitle track.
Code
The application uses Next.js, TypeScript, Tailwind, a shadcn-style button component, FastAPI, Pydantic and SQLite. Temporal's Python SDK supplies the workflows, Activities, signals and durable timers. Ollama serves Ministral locally.
The application code is MIT licensed; model weights retain their upstream licenses. Manual setup uses a persistent local Temporal service, the Python worker, FastAPI, Next.js and Ollama. The optional Docker Compose configuration has not been verified and uses the explicitly documented inline mode with reminders disabled.
How I Built It
The model's job is extraction, not authority. Ministral receives the imported text, its reference timestamp, the caregiver names and the approved tasks it is allowed to see. It returns structured suggestions against a typed JSON schema. The application has no fake model-response fallback.
A valid JSON object is only the first check. Every suggestion must cite the exact source ID and a verbatim contiguous quote from that source. An invalid quote rejects the extraction before suggestions are saved. Dates interpreted by the model carry a review warning. Ambiguous times remain unresolved; a mismatched timezone requires manual confirmation.
The review screen places those original words beside editable fields for the title, category, date, location, proposed caregiver and open questions. That is where a person decides whether the suggested item accurately represents the conversation.
Approval and acceptance are separate state transitions. Approval puts the item on the shared plan. Acceptance belongs to the proposed caregiver, or to someone volunteering for an unassigned item. A coordinator cannot turn another person's proposed name into an accepted commitment.
The board and calendar read the same approved records. Unclaimed travel stays visible. Availability checks compare tasks with recorded unavailable windows and other responsibilities, using a documented one-hour planning estimate. CareRelay does not infer journey times or pretend to know whether two errands are realistically compatible.
An appointment change retains its history. The reviewer selects the approved item being replaced; approval cancels that item and creates an active replacement without carrying acceptance across. Related transport remains a separate responsibility that needs its own review and consent.
I applied that same boundary to reminders. Scheduling requires an approved active task, an explicit acceptance by the signed-in owner, a current task version and a future timezone-aware reminder time. Accepted responsibilities have a consent generation identifier. Repeating an acceptance request does not manufacture a new generation, while a fresh acceptance cannot silently revive an obsolete reminder.
Each reminder gets a stable workflow ID and an idempotent scheduling request ID. SQLite commits the reminder before dispatch. If the API stops between Temporal accepting the workflow and the dispatch marker being saved, retrying that start cannot create a second execution.
Inside the workflow, an Activity loads the current reminder state from local storage. The workflow waits on a durable timer and can receive a payload-free refresh signal when the person changes its time, snoozes it, completes the responsibility or cancels the reminder. Signals prompt a reload of authoritative state; they do not carry family messages or instructions to invent a new assignment.
Snooze postpones the reminder. Choosing an earlier time requires the explicit reschedule control. Every time change increments a revision, so a delayed Activity for an obsolete revision cannot deliver against the current schedule.
When a timer becomes due, the delivery transaction checks the task's existence, current owner, acceptance generation, source visibility, state, revision and deadline. It then inserts the in-app event using a unique reminder/revision key. Temporal Activities may execute again after a failure; the database boundary prevents that repetition from creating a duplicate local reminder. Snoozing can intentionally create a later event for a new revision.
Task completion and approval of an appointment cancellation or reschedule update reminders atomically with the task. A deleted responsibility is detached and cancelled during reconciliation. The replacement appointment has no reminder until someone accepts it and schedules one. None of these paths contacts a caregiver automatically.
The worker uses separate queues and concurrency slots for inference and reminders, so a busy model Activity does not occupy the reminder worker's delivery slot. Temporary reminder-storage failures retry with bounded exponential backoff, up to five attempts and a three-minute overall Activity deadline. An exhausted or stopped workflow becomes a visibly cancelled reminder requiring attention rather than a false success.
Temporal also protects source imports. FastAPI saves the source and queued job transactionally, and an outbox dispatches its stable workflow ID. The extraction worker heartbeats during genuine Ollama inference, rechecks import permission before committing, and rejects results from stale attempts. An API restart can therefore resume pending work without another source submission.
Privacy applies before material reaches the model or the browser. A source can be circle-visible or private to its importer. Coordinator status does not grant access to another person's private source. Import, review and handoff permissions are enforced by the backend. Reminder status and notifications are visible only to their owning caregiver, and their task titles remain filtered if access changes.
Workflow payloads exclude family messages, task titles, locations, caregiver names, access tokens and consent identifiers. They contain opaque IDs, status/revision values and timer intervals. Temporal necessarily retains timing metadata. Generic Activity errors keep private storage details out of workflow failures.
The handoff feature has its own factuality boundary. The model selects references to supplied approved tasks; the backend validates those references and renders the brief from approved records. It includes all relevant tasks to prevent model omissions, excludes private sources, and separates accepted commitments from unresolved responsibilities. Human approval snapshots task versions. A changed plan requires a fresh brief before copying.
I tested failure behavior with actual Temporal execution and local inference. In an isolated synthetic run, I stopped the worker across an eight-second timer, restarted it and observed one delivery. Duplicate requests and refresh signals produced no second event. Snooze produced one event for its new revision. An actual SQLite write lock exercised backend retries. Appointment changes and deletion stopped obsolete reminders, while the unclaimed return ride remained unassigned.
That exercise took 53.36 seconds. It is one reproducible failure test, not a reliability percentage or latency benchmark. The recorded demonstration independently shows the same central restart boundary with a 20-second timer.
All 36 deterministic backend/evaluation tests pass, covering consent, private access, stale acceptance, duplicate delivery, reminder lifecycle changes and the coordination workflow. TypeScript checking, the production build and a genuine Chromium import/review/acceptance/handoff journey also pass. Desktop and mobile reminder checks verified scheduling, browser refresh and completion without detected page errors or horizontal overflow.
Extraction was measured separately on 32 labelled synthetic messages. The development-set run recorded 92.9% strict category precision and 96.3% recall: 26 true positives, two false positives and one false negative. Owner attribution was 11/12, explicit timestamps 21/22 and change operations 3/3.
Those are development-set results, not held-out accuracy. Prompt refinement used that same corpus. One remaining disagreement concerns grocery collection as a pickup versus an errand; another extra suggestion came from an availability caveat. A genuine quote establishes provenance, not the correctness of every inferred field. Human review remains necessary.
CareRelay is a fictional-data local prototype. It does not provide production identity verification or encrypted SQLite storage. Its profile switcher demonstrates role and consent boundaries rather than independent household authentication. Its timers can recover late after downtime, and bounded failures still need attention. No household time savings, clinical outcomes or statistical reminder-reliability rate have been measured.
Why Does Open Innovation Matter?
Local model weights let the core workflow run without sending family messages to a hosted inference API. Once the required software and weights are installed, CareRelay can use local inference and a local Temporal service. There is no paid inference dependency in the demonstrated path.
The extraction model can be replaced, its prompt inspected and its outputs measured against the included synthetic corpus. The schemas and validators expose what the application accepts as evidence. Temporal makes the waiting and recovery behavior inspectable too: a timer firing, a repeated Activity or a cancelled workflow leaves an execution history that can be checked against the resulting local records.
The useful part of openness is being able to challenge the implementation. Someone else can run the same synthetic case, stop the worker, repeat an event and inspect whether a second reminder appears. They can examine where source visibility and acceptance are checked instead of relying on a reassuring demo alone.
Open components make inspection and replacement possible. CareRelay's surrounding decisions supply the accountability: preserve the quote, expose uncertainty, require consent and keep obsolete responsibilities from quietly returning.
The Lazy Payoff
The repetitive burden is not just remembering an appointment. It is reopening the chat to check which date is current, asking whether a proposed driver actually agreed, and reconstructing the plan for the next person.
CareRelay brings those details into a review queue, an approved shared plan and a grounded handoff. Its reminder workflow takes over the waiting while preserving the person's decision to accept, postpone, complete or cancel.
The synthetic demonstration shows one concrete payoff: restarting the worker does not require the caregiver to recreate the reminder, and approving an appointment change removes the obsolete reminder. It also shows the boundary that matters just as much: the return ride is still unassigned. Software persistence cannot substitute for someone's yes.
Alex still has to ask whether Maya can drive. Maya still gets to decide. At least neither of them has to start by reconstructing the entire conversation again.
Prize Categories
I am entering the overall Week 3 challenge and Best Use of Temporal. CareRelay uses durable Temporal timers and workflows for explicitly accepted responsibilities, with worker-restart recovery, snooze and cancellation signals, bounded backend retries and idempotent in-app delivery. The demonstration includes real worker shutdown/restart, an observed reminder delivery and cancellation after a reviewed appointment change. Temporal also orchestrates the local AI extraction pipeline.




Top comments (0)