Skip to main content

Overview

CareSupport’s runtime is composed of single-purpose scripts that handle message processing, polling, webhooks, review, and maintenance. All scripts import from runtime/config.py for paths and settings. Location: runtime/scripts/

Core Pipeline Scripts

sms_handler.py

The 13-step pipeline that processes inbound messages and generates responses.
python runtime/scripts/sms_handler.py --from "+1..." --body "test message" --dry-run
Pipeline stages:
1

Phone resolution

Resolve phone → family → member → role → access level
2

Context loading

Load family.md and member-specific context
3

Pre-filter (ENFORCEMENT)

role_filter.filter_family_context() redacts sections based on access level
4

PHI audit (ENFORCEMENT)

phi_audit.log_context_load() logs who accessed what
5

AI generation

Call Claude via OpenRouter/Anthropic with filtered context
6

Post-check (ENFORCEMENT)

role_filter.check_outbound_message() scans for leakage
7

Approval classification

approval_pipeline.classify_updates() detects if confirmation needed
8

File updates

family_editor.apply_updates() applies changes with backup
9

Response

Return response for delivery (handler doesn’t send directly)
Arguments:
  • --from - Phone number (E.164 format: +16517037981)
  • --body - Message text
  • --dry-run - Process without sending
  • --service - Transport service (default: iMessage)
Location: runtime/scripts/sms_handler.py:1

poll_inbound.py

Polls Linq for new inbound messages and processes them through sms_handler.py.
This is the polling fallback. The preferred path is webhook_receiver.py (push-based, real-time). Use polling only when webhooks aren’t available.
python runtime/scripts/poll_inbound.py --once
What it does:
  1. Lists recent inbound messages from Linq API
  2. Filters out already-processed messages (tracked by message ID)
  3. Processes each new message through sms_handler.py
  4. Sends responses via Linq
  5. Handles outreach to other family members
  6. Auto-registers outreach recipients in routing.json
Arguments:
  • --once - Run once and exit (for cron)
  • --interval - Seconds between polls (default: 15)
Processed message tracking: .processed_sids.json in runtime/scripts/ Location: runtime/scripts/poll_inbound.py:1

webhook_receiver.py

Real-time webhook receiver for Linq Partner API events.
python runtime/scripts/webhook_receiver.py --port 8080
Features:
  • HMAC-SHA256 signature verification
  • Replay attack prevention (5-minute window)
  • Routes through full sms_handler.py enforcement pipeline
  • Webhook event logging to logs/webhooks/
Event types handled:
  • message.created - New inbound message
  • message.updated - Message status change
  • chat.created - New conversation started
Enforcement preserved:
  • role_filter pre-filters context by access level
  • phi_audit logs every PHI access
  • Leakage post-check scans outbound messages
  • approval_pipeline gates medication/member changes
Location: runtime/scripts/webhook_receiver.py:1

Transport Scripts

linq_gateway.py

Linq Partner API V3 client for iMessage-first messaging.
python runtime/scripts/linq_gateway.py create --to "+16517037981" --body "Hello" --service iMessage
API functions:
  • create_chat(phone, message, service) - Start new conversation
  • send_message(chat_id, message) - Send to existing chat
  • list_chats() - Get all active conversations
  • get_messages(chat_id, limit) - Fetch message history
  • start_typing(chat_id) - Show typing indicator
  • mark_as_read(chat_id) - Mark conversation as read
  • send_reaction(chat_id, message_id, reaction) - React to message
Configuration: runtime/scripts/linq_config.json
{
  "linq_api_token": "your-token",
  "linq_phone": "+16517037981",
  "webhook_signing_secret": "your-secret"
}
Location: runtime/scripts/linq_gateway.py:1

Review & Learning Scripts

review_loop.py

Rule-based conversation review that catches mechanical violations and generates findings.
python runtime/scripts/review_loop.py --since 2h
Two tiers of review:
  1. Mechanical tier (automated)
    • Multi-question detection
    • Forbidden phrase usage
    • Skill violation patterns
  2. Contextual tier (requires Opus)
    • Agent contradicting itself
    • Missing member context
    • Flows with no protocol
Without --stage: Every run writes lessons to real files (mutations) With --stage: Findings → staging/reviews/ (scratch pad, no mutations) Arguments:
  • --since - Time window (2h, 24h, 7d)
  • --family - Specific family ID
  • --full - Include full transcript in output
  • --stage - Write to staging (no production changes)
  • --json - JSON output format
  • --dry-run - Preview only
Location: runtime/scripts/review_loop.py:1

review_staging.py

Staging environment for review testing - prevents production mutations during testing.
python runtime/scripts/review_staging.py snapshot --family kano
Three piles:
  • Accumulates with each --stage run
  • Cleared on reset
  • You don’t care about most of these
  • Reviews flagged as worth revisiting
  • Survives resets
  • Opus’s reading pile for proposals
  • Future use for AI-generated improvements
  • Markdown format (not schema)
  • Can surface unexpected gaps
Staged testing protocol:
1

Setup (once per session)

review_staging.py snapshot --family kano
Locks baseline - your safety net
2

Test loop (repeat as needed)

review_loop.py --since 3h --family kano --full --stage  # run 1
review_loop.py --since 3h --family kano --full --stage  # run 2
review_staging.py list --family kano                     # see results
review_staging.py save --family kano --review {ts} --name finding-name
review_staging.py reset --family kano                    # restore + clear
Nothing permanent happens here
3

When ready (one-way door)

review_staging.py promote --family kano --review {ts} --items 0,1
This is the ONLY moment real files change
Location: runtime/scripts/review_staging.py:1

Cron Scripts

heartbeat.py

48-hour lookahead scanner that reads family.md and returns alerts.
python runtime/scripts/heartbeat.py --family-dir /path/to/family
Alert types:
  • Uncovered shifts - No one assigned or status=uncovered
  • Med coverage gaps - Shift requires med_admin capability but caregiver lacks it
  • Appointment logistics - Appointments within 48h missing transport or escort
  • Tentative shifts - Shifts not confirmed
Self-contained: Reads family.md, parses YAML schedule blocks, evaluates rules. Does NOT use AI - fully deterministic. Output format:
{
  "family_id": "kano",
  "scan_time": "2026-02-18T10:00:00Z",
  "lookahead_hours": 48,
  "alerts": [
    {
      "severity": "high",
      "category": "uncovered_shift",
      "summary": "Feb 19 morning shift uncovered",
      "date": "2026-02-19",
      "window": "07:00-12:00",
      "hours_until": 21.0
    }
  ],
  "all_clear": false
}
Location: runtime/scripts/heartbeat.py:1

maintenance.py

Garbage collection and validation for family.md.
python runtime/scripts/maintenance.py --family-dir /path/to/family
Pruning rules:
SectionStrategy
ScheduleKeep current + next 2 weeks. Past shifts removed.
Recent EventsKeep last ~50 entries. Oldest pruned first.
Active IssuesResolved issues ([x]) removed.
AppointmentsPast appointments removed.
PatternsManual review - not auto-pruned
MembersManual review - not auto-pruned
MedicationsOnly pruned when discontinued
Consistency checks:
  • Members referenced in Schedule exist in Members section
  • YAML blocks still parseable
  • Required sections present
  • No orphaned member references
Uses family_editor backup/validate for safety. Location: runtime/scripts/maintenance.py:1

Utility Scripts

prompt_builder.py

Assembles the system prompt for AI calls.
from prompt_builder import build_system_prompt

system_prompt = build_system_prompt(
    family_context="# Kano Care Network...",
    member_name="Sarah",
    member_role="Professional Caregiver",
    access_level="schedule+meds"
)
Components loaded:
  • SOUL.md - Agent identity
  • runtime/learning/capabilities.md - CAN/CANNOT list
  • runtime/learning/lessons.md - Corrections (max 20)
  • Filtered family context
  • Access level constraints
Location: runtime/scripts/prompt_builder.py:1

care_router.py

Model cost optimization - routes messages to appropriate tier.
from care_router import route

tier = route(inbound_message="Can someone cover Tuesday morning?")
# Returns: "fast" | "reason" | "critical"
Tiers:
  • fast - Haiku 4.5 (simple queries, confirmations)
  • reason - Sonnet 4.6 (scheduling, coordination)
  • critical - Opus 4.6 (complex conflicts, sensitive situations)
Location: runtime/scripts/care_router.py:1

session.py

Session management for cache reuse observability.
from session import get_or_create

session = get_or_create(phone="+16517037981", family_id="kano")
print(f"Session {session.session_id} - message #{session.message_count}")
Location: runtime/scripts/session.py:1

reaction_handler.py

Handles message reactions (thumbs up/down for feedback). Location: runtime/scripts/reaction_handler.py:1

Configuration

runtime/config.py

Single source of truth for all paths and settings. Every runtime script imports from here.
from config import paths, linq, twilio

# Get family file
family_file = paths.family_file("kano")

# Get Linq credentials
api_token = linq.api_token

# Get logs directory
logs_dir = paths.logs
Path resolution:
  • All paths derived from CARESUPPORT_ROOT env var (defaults to /work)
  • No hardcoded absolute paths allowed
  • Tested by test_structural.py
Location: runtime/config.py:1

Build docs developers (and LLMs) love