Skip to content

Backend

GiveCare's current gc-sms backend is a compact v2 Convex service for SMS support. Current-tense architecture claims should use the v2 convex/ and src/ files first1.

Current v2 runtime

The active backend contract is the V2 convex/ and src/ runtime. The live system is best read as a harness-owned SMS turn pipeline with a compact Convex schema23.

What the backend owns

Today the backend owns five broad kinds of state and behavior1:

  1. Caregiver identity and consent — phone identity, org attribution, consent timestamps, phase, and loop stage
  2. Message and delivery ledgers — inbound/outbound message records, Twilio SIDs, pending outbound rows, and delivery callbacks
  3. Care memory and assessments — namespaced memory facts plus SDOH6, CWBS14, BSFC-s, and EMA3 assessment runs with scores and zone subscores
  4. Safety and resources — operational safetyEvents, grounded resourceCatalog rows, and crisis lifecycle state
  5. Turn operations — async jobs, per-turn traces, referral codes, and harness health reporting

Core Live Tables

Group Tables What they hold
Identity + tenancy caregivers, orgs, referrals, signupAttempts phone identity, org isolation, consent, journey state, SHARE codes, signup evidence
Messaging + jobs messages, jobs inbound/outbound ledger, pending outbox rows, async turn queue
Memory + assessments memory, assessmentRuns model-visible and harness-only facts, scored assessment history with per-zone subscores
Safety + resources safetyEvents, resourceCatalog crisis lifecycle records, read-only grounded resources
Observability traces, alertState per-turn evaluator decisions, token usage, cost; alert cooldown state for error-rate monitoring
Email + subscribers subscribers, emailSends, emailSuppressions unified email list across web surfaces, send dedup ledger, suppression list

Live Inbound Path

flowchart TD
    A["Twilio inbound webhook"] --> B["convex/http.ts signature check"]
    B --> C["agent.ingestInbound"]
    C --> D{"Known caregiver?"}
    D -->|No| E["Signup redirect SMS"]
    D -->|Yes| F["Persist inbound message"]
    F --> G["scheduler.enqueueJob"]
    G --> H["scheduler.processDueJobs"]
    H --> I["agent.runTurn"]
    I --> J["Policy gates"]
    J --> K{"Deterministic?"}
    K -->|Yes| L["Commit deterministic reply"]
    K -->|No| M["Build context + run Pi/Gemini"]
    M --> N["Evaluate reply + effects"]
    L --> O["agentDb.commitTurn"]
    N --> O
    O --> P["Pending outbound message"]
    P --> Q["outbound sender + Twilio callback"]

Turn Execution Model

The current runtime separates host-owned guarantees from model-owned language and judgment2.

Layer Current responsibility
Policy gates STOP/HELP/SHARE, pending consent YES, START, consent gate, crisis detection
Context builder recent messages, durable/volatile memory selection, chief-of-staff brief, care guidance, resource context
Pi/Gemini path open-ended support, typed capture tools, Convex-backed lookup/resources, assessment/eligibility tools, proactive turns
Evaluator pre-commit checks for safety language, SMS length, clinical claims, caregiver-first posture, operational next step, and forbidden writes
Commit boundary pending outbound row, approved memory writes, caregiver profile patch, assessment completion, trace, safety event, job completion

The practical unit of orchestration is not "a model reply"; it is a committed turn outcome. convex/agentDb.ts:commitTurn records the outbound message before Twilio send, applies only approved memory writes, records the trace, optionally opens a safety event, and marks the job complete. Approved follow-up requests are enqueued through convex/scheduler.ts after the commit boundary so scheduler policy remains centralized1.

The current turn host delegates rules that do not need Convex state to pure modules: memory keys live in src/memoryKeys.ts, normalization and merge semantics live in src/memory.ts, chief-of-staff posture lives in src/turn/chiefOfStaff.ts, and policy/post-processing live in src/turn/pipeline.ts2.

Scheduler and Outbox

The live scheduler is an async job queue. It claims due jobs, respects outbound rate limits for non-inbound work, and schedules agent.runTurn for execution. Outbound SMS uses a transactional outbox pattern: the commit inserts a pending outbound messages row, convex/outbound.ts sends pending rows, and convex/outboundDb.ts records Twilio delivery status1.


  1. GiveCare. "Data Agent SMS Runtime (Convex code)." Source -> 

  2. GiveCare. "SMS Journey Orchestration Contract." Source -> 

  3. GiveCare. "GiveCare Backend Specification." Source ->