Skip to main content
Glama

KinKeeper — proactive care-coordination companion (Alexa+ track demo)

Safety notice — read first. KinKeeper is a synthetic care-coordination demo. The senior ("Maggie Rivera") is a fictional persona and every check-in, quote and card is generated locally from invented text. KinKeeper is not a medical device, provides no medical diagnosis, monitoring or advice, and cannot contact emergency services. It never sends real notifications — no push, SMS, email or voice call ever leaves this machine; family "notifications" are cards that wait in a local inbox page. It uses no real personal data, no credentials, no paid APIs, and no external network calls.

Built for the Amazon Developer Hackathon — Alexa+ track: a self-hosted MCP server (Model Context Protocol spec 2025-11-25 over Streamable HTTP) plus a web-simulated Alexa+ experience, as explicitly permitted by the track rules.

What it does

KinKeeper closes a proactive care loop for a senior living alone — nobody has to ask:

  1. Scheduled daily check-in. The companion greets the senior each morning; what they say is recorded into a longitudinal care journal via the MCP tool record_checkin.

  2. Cross-session memory. The companion recalls prior days verbatim: "You've mentioned your knee before — on Thursday, Oct 1 and Friday, Oct 2."

  3. Deterministic rules, not vibes. A rules engine (R1 missed-check-in, R3 repeated-topic) runs against the event store on a scheduler tick. When the 09:00 check-in plus a 45-minute grace passes with no word, the rule fires — deterministically.

  4. The system speaks first. After a missed check-in the companion proactively opens: "I hadn't heard from you yet today — how are you feeling?"

  5. Actionable family inbox. A vague reply mentioning a fall escalates via assess_risk → notify_family → an amber card with the senior's verbatim quote and a suggested action ("Call Maggie today"). The card waits in the local inbox; nothing is ever sent externally.

  6. Weekly digest. get_weekly_digest summarizes completion, mood trend, recurring topics with quotes, and risk days.

Related MCP server: Hearth MCP Server

Architecture

┌─────────────────────────────── one local Node process ───────────────────────────────┐
│                                                                                      │
│  public/ (web)          src/orchestrator.js        src/mcp/server.js                 │
│  Simulated Alexa+  ──▶  Simulated companion  ──▶   MCP server (6 tools)              │
│  chat / inbox /         (deterministic             record_checkin                    │
│  journal / audit        dialogue engine)           get_care_journal                  │
│        │                      │                    assess_risk                       │
│        │ REST /api/*          │ MCP client         notify_family                     │
│        ▼                      ▼ (official SDK,     schedule_followup                 │
│  ┌───────────────────────────────────────────▶    get_weekly_digest                  │
│  │  POST/GET/DELETE /mcp — Streamable HTTP, spec 2025-11-25, stateful sessions  │    │
│  └──────────────────────────────────────────────────────────────────────────────┘    │
│        │                                                                             │
│  src/scheduler.js (proactive ticks) ──▶ src/rules.js (deterministic R1/R3)           │
│        │                                                                             │
│        ▼                                                                             │
│  src/store.js — SQLite event store: events · inbox_cards · followups · audit         │
└──────────────────────────────────────────────────────────────────────────────────────┘

The companion reaches care capability only through the MCP protocol — an independent MCP client (or the official MCP Inspector) can call the same six tools at http://localhost:8787/mcp. Every JSON-RPC call is persisted to the audit trail (mcp-in / mcp-out / system rows), available via GET /api/audit. The showcased web UI (Today / Family updates / Safety / Explore the demo) deliberately keeps this protocol evidence out of the product views; this README, the tests, and the audit API are the technical proof.

The web UI's conversation pane is session-only (it clears on reload, and the Safety view says so); the journal, family cards, follow-ups, and audit trail persist in SQLite.

Quick start

Requires Node.js 22 (developed on Node 22 / macOS arm64). better-sqlite3 is a native module compiled for a specific Node.js major version — if you switch Node versions you will see ERR_DLOPEN_FAILED / NODE_MODULE_VERSION mismatch errors. Fix by running KinKeeper with Node 22, or rebuild the module for your current Node:

npm rebuild better-sqlite3

No accounts, keys or network access needed beyond npm install.

npm install
npm start          # serves everything on http://localhost:8787 (loopback only)

Open http://localhost:8787/ — the first screen is Maggie's Today view with her check-in status and one clear action. The Explore the demo view walks the two-minute story in plain language (check-in → quiet morning → KinKeeper speaks first → vague fall reply → amber family card → weekly summary); Dana's cards live under Family updates, and Safety states the fictional-data, no-notification, no-emergency, and no-medical-advice limits.

npm test           # unit tests: deterministic rules + fact extractor + idempotency
npm run verify     # end-to-end: independent MCP client, full scenario, restart persistence
npm run seed       # reseed synthetic data (add -- --reset to wipe and reseed)

Network binding & access control

The server binds to 127.0.0.1 (loopback only) by default, because the demo exposes raw journal/audit reads, MCP writes, reset and time-warp endpoints. To bind beyond localhost you must opt in explicitly and set a bearer token — the server refuses to start otherwise:

KINKEEPER_HOST=0.0.0.0 KINKEEPER_TOKEN=choose-a-token npm start

With a broad bind, every /api/* and /mcp request from a non-loopback client must send Authorization: Bearer <KINKEEPER_TOKEN>; loopback clients stay unrestricted. Static assets remain public (they contain no data). Even with a token, this is a hackathon demo — do not expose it to the public internet.

Idempotency & negation handling

  • Mutating MCP tools are idempotent. record_checkin accepts an idempotency_key; notify_family and schedule_followup accept dedupe_key. A replayed call returns the originally recorded event/card/follow-up — including its original ID — instead of creating a duplicate or answering with a cardless acknowledgment. The built-in MCP client (src/mcp/client.js) only retries a failed call when it is truly side-effect-free or carries such a key — everything else fails honestly instead of being re-sent. The orchestrator's escalation_completed audit event likewise carries a per-check-in dedupe key (esc-completed:<event_id>), so replaying the same message returns the deduplicated card/follow-up without appending a second completion record, while a genuinely new check-in is still recorded exactly once.

  • Audit-producing reads are not silently retried. get_care_journal is the only side-effect-free tool. get_weekly_digest and assess_risk compute from read-only data but deliberately append an audit event on every call (digest_generated / risk_assessed) so the demo can show real usage; because of that they are not classified as safe-to-retry, and repeated calls honestly produce repeated audit events rather than pretending to be pure reads.

  • Fact extraction is negation-aware (src/extract.js). Statements are parsed per clause: "I did not fall and I have no chest pain" yields no risk flags (the denied mentions are reported as negated_flags), "I had not taken my meds today" yields meds_taken: false, and "I did take my pills though" yields meds_taken: true. meds_taken is tri-state (true / false / null = not mentioned) so the UI never asserts a wellness fact the senior did not state. An explicit meds_taken: false check-in always returns an amber "Today needs a little attention" daily card — never a green "Today looks good" — and adds a small, capped, non-escalating signal to the deterministic risk score (a status reflection, not a diagnosis).

  • A late reply resolves the missed-check-in card. When a check-in is recorded for a date, that day's R1 "missed check-in" card is rewritten to say the reply was received (with the timestamp) instead of claiming KinKeeper is still awaiting one. This factual update applies whether the card is still open or already acknowledged — an acknowledged card keeps its acknowledged (seen) status, but its body and source are corrected so the family timeline never states something that is no longer true. Proactive prompts distinguish a missed check-in opener from a risk follow-up in both copy and the kind field.

Dana's family action loop & card evidence

Escalation and missed-check-in cards are not dead ends: Dana can record a clear human next step right on the card — Plan a call, Tried to call, Reached Maggie, or Follow up later (POST /api/inbox/:id/action). The action loop is truthful by construction:

  • It only records what Dana says she did or plans. No phone call is placed, no message or notification is sent, nothing is concluded medically, and there is no emergency response. Every response carries a truth_note saying exactly that.

  • Mark as seen stays separate. Acknowledgement is an inbox state (POST /api/inbox/:id/ack); action steps are a distinct record and do not change open/seen status. Like the action loop, ack requires the owning senior_id: a missing/unknown senior or a cross-senior ack is rejected with 400, an unknown card with 404, and no rejected call mutates anything. A duplicate ack replays the card's current state without a second seen record.

  • One record per (card, action). A unique dedupe key makes a double submit return the original record (deduplicated: true) instead of a duplicate timeline entry. Once Reached Maggie is recorded the loop is complete and no further steps are offered.

  • Validation guards the target. The claimed senior_id must exist and must own the card; unknown actions and non-actionable (informational) cards are rejected with 400, unknown cards with 404.

  • Real timestamps only. Steps are stamped with the demo's virtual clock. Cards acknowledged before the ack_ts column existed show "seen" without an invented time.

Each card renders a persistent, chronological timeline — card created, Maggie's reply if any, seen by family, and Dana's recorded steps — computed server-side from the event store (card_actions table + family_action_recorded / family_card_seen events, both created by safe additive migrations on existing SQLite files) so it survives refresh and restart.

An expandable "Why this card?" panel explains each card in plain language: the exact source quote when one exists, the observed timing/check-in/reply facts, and at most relevant 7-day context from the actual journal (e.g. "She also mentioned 'fall' on Thu, Oct 3."). The context window is anchored at the card's creation time — it describes what was true when KinKeeper placed the card, so a later event (even another fall the next day) never rewrites an old card's rationale; later facts appear on the card's timeline instead. The panel never shows rule IDs, scores, or audit internals, and it never re-interprets risk beyond what was observed.

MCP tools (self-hosted, spec 2025-11-25, Streamable HTTP)

Tool

Purpose

Key output

record_checkin

Store a check-in transcript; deterministically extract sleep / meds / activity / mood / risk phrases / watched topics

structured facts + daily status card

get_care_journal

Longitudinal history for cross-session recall

dated entries with excerpts

assess_risk

Transparent rule-based score over recent events in a rolling window

score, level, escalate, reasons, escalate_semantics

notify_family

Place an actionable card in the local family inbox

delivered_externally: false + card

schedule_followup

Queue a proactive re-engagement

due timestamp

get_weekly_digest

7-day completion / mood / recurring topics / risk days

digest card payload

assess_risk.escalate is a rolling-window threshold, not a this-turn decision. It stays true for as long as an earlier adverse event keeps the window score at or above the threshold — so a benign new utterance can still return escalate: true. It never by itself creates a card or sends anything (nothing is ever sent externally; cards wait in the local inbox). The per-turn action signal is the orchestrator's escalated field in the POST /api/chat response: true when that message itself qualified for family escalation and the inbox holds the corresponding card — newly created, or reused idempotently when the exact same message is replayed (notify_family returns the original card with card.deduplicated: true, so no second card appears). The additive card_created_this_turn flag is true only when this turn actually minted the card. The UI keys "a card is waiting in Family updates" off escalated, never off the assessment score.

Deterministic rules

Rule

Trigger

Action

R1 MISSED_CHECKIN

No check-in by checkin_time + grace_minutes

proactive prompt + amber inbox card with suggested action

R3 REPEATED_TOPIC

Watched concern on ≥3 distinct days in 7

info card for family + digest highlight

Rules are pure functions (src/rules.js) — same inputs, same outputs, unit-tested. The demo "fast-forward" button only moves the virtual clock (src/clock.js); it never touches rule logic, and every clock advance is itself audit-logged.

Honest engineering notes / limitations

  • The companion's dialogue is a deterministic template engine (src/orchestrator.js

    • src/extract.js), deliberately not an LLM and not Amazon Bedrock: this build avoids paid APIs and credentials, keeps every turn reproducible, and claims no external integration it does not perform. The MCP boundary is where an LLM agent (or Alexa+ itself) would attach.

  • The Alexa+ experience is simulated in the web app, a path the track rules explicitly allow; no Alexa+ endpoint, account or trademark assets are used.

  • English transcripts only; one synthetic persona; local-only by default (loopback bind; broad binds require an explicit bearer token — see above); voice input/output uses the browser's built-in Web Speech API when available, with text fallback.

  • notify_family is intentionally a local inbox write. The audit trail records delivered_externally: false on every call.

  • What persists across a refresh/restart (and what does not). The care journal, family inbox cards, follow-ups, audit trail and the virtual clock all live in the SQLite event store and survive page refreshes and server restarts — the Today view's status banner is rendered from that persisted state (last_checkin / last_risk in GET /api/state), so it can never contradict the journal after a refresh. The chat bubbles are intentionally session-only: they are a presentation of the current conversation, not a record — the durable record of every turn is the journal entry and the audit trail (journal and cards are visible in the Today and Family updates views after a refresh; the audit trail is available via GET /api/audit).

Relationship to other submissions

KinKeeper is a new, independent project created during the hackathon window. It shares no code, assets, or concept with the author's earlier, separate submission "Show, Don't Tell": KinKeeper is a server-centric proactive care-coordination system built around a self-hosted MCP server, deterministic rules and a persistent event store — a different track concept, architecture and codebase.

License

MIT — see LICENSE.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables an older adult to talk with Alexa+ about medicines and daily routine while a caregiver sees a calm, consent-gated dashboard and push alerts only when a genuine pattern (e.g. an unusually late first activity) appears. Includes elicitation-based consent, emergency bypass, resumable SSE streams, and an inline MCP App view.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables an Alexa+ family concierge to personalize household evening plans, suggest timelines, create reminders, and log gentle elder/accessibility care check-ins through MCP tools, resources, and prompts. It supports real local MCP invocation over Streamable HTTP with virtual Bedrock-style AWS demo behavior.
    4 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables a voice assistant to run daily check-ins with family-written questions, record hedged answers honestly rather than as confirmed, reschedule follow-ups until a set time, and email a caregiver when a loop stays open. Includes a status summary, pausable check-ins, and a rendered result card for clients that support MCP Apps.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables consented, daily Alexa check-ins that score speech and memory answers against a personal baseline, flag sustained drift to family, produce clinician summaries, and export de-identified data for research. It also provides MCP tools, resources, prompts, and MCP Apps views for compatible agent hosts.
    3 npm
    MIT