Skip to content

PostgreSQL

PostgreSQL is the authoritative data store for every domain in chris-os: messaging, health, calendar, contacts, financial, activity, config, memory, and more. All pipelines write here; all analytics read from here.

Migration level: 302 Total tables: 210 across 5 schemas Total rows: ~11.5M+ (active tables) Indexes: 660 Functions: ~85 application-defined


SchemaTablesPurpose
public183All production data: messages, health, calendar, activity, config, dispatch
memory17Memory server: embeddings, entities, knowledge graph
brewing13Homebrew recipes and sessions (BrewersFriend sync)
ha2Home Assistant state change events
therapy4Tier 1 Sacred — isolated, empty, therapy_app role only

TableRowsNotes
messages450K+Primary iMessage/email/SMS table. Columns: source, direction (‘inbound’/‘outbound’), received_at TIMESTAMPTZ, body, contact_id, embedding vector, search_vector tsvector.
social_messages150Facebook/Instagram DMs. UUID PK.
discord_messages870Discord messages. UUID PK. Columns include guild_id, channel_id, author_id, is_bot, director_escalated.
dialogue107,555GLaDOS session dialogue log.
imessage_conversations2,444iMessage conversation metadata.

Canonical cross-platform view: all_messages — see Views section below.

TableRowsNotes
health_records9.5M+Apple Health export. TEXT PK (hash-based). Columns: record_type, source_name, value, start_date TIMESTAMPTZ, record_hash (unique).
peak_state_scores583Daily scores. Columns: overall_score, physical_score, social_score, scheduling_score, environment_score, financial_score, indicators JSONB.
workouts0Workout sessions. Columns include workout_type, duration_minutes, started_at TIMESTAMPTZ, workout_hash (unique).
time_blocks301Time Portrait blocks. Columns: start_time, end_time, category, subcategory, source, confidence, corroboration_score.
TableRowsNotes
calendar_events6,850Google Calendar. TEXT PK. Columns: source, external_id, start_time TIMESTAMPTZ, attendees JSONB, embedding vector. Unique on (source, external_id).
weather_data53Daily weather records.
activity_timeline683,052Cross-source activity feed (materialized).
TableRowsNotes
contacts5,400+Master contact record. TEXT PK. Columns: name, identifiers[], phone_numbers[], email_addresses[], relationship, priority, discord_id.
contact_cadence_stats4,922Computed communication cadence per contact.
relationship_scores4,922Computed relationship strength scores.
TableRowsNotes
activity_timeline683,052Materialized cross-source activity feed.
web_activity338,983Browser activity.
signals35,779Raw signal events.
github_commits816GitHub commit history mirror.
github_issues588GitHub issues mirror.
photo_metadata41,964Photo library metadata.
TableRowsNotes
documents484+Master document store. UUID PK. Columns: title, slug, content, format, category, tags[], version, parent_id, metadata JSONB, status, superseded_by. Trigger archives to document_versions on UPDATE.
claim_registry35Validated factual claims with confidence, evidence_query, superseded_by chain. UUID PK.
discovery_questions0Cornerstone Discovery Engine interview questions.
cornerstones0Cornerstone identity entries.
TableRowsNotes
config_registry_item7The Manifest: items to track. Columns: component, host, property, expected_expression, stale_after INTERVAL, tracking_mode (‘asserted’/‘observed’).
config_registry_observation118,440Observed values per config item.
config_registry_event_inbox219,285Inbox for incoming config events.
schema_migrations34Migration tracking. Columns: version TEXT PK, applied_at TIMESTAMPTZ, checksum, description.
reportcard_snapshots153Daily operational health snapshots.
TableRowsNotes
dispatch_sessions175Agent dispatch session records.
dispatch_agents4,195Individual agent records.
dispatch_activity10,533Activity log per agent.
ops_escalations105Active and historical escalations.
session_lifecycle_events914Preflight/postflight lifecycle events.
morning_council_snapshots8Morning Council briefing snapshots.
TableRowsNotes
unifi_clients86UniFi network clients.
backup_log140R2 offsite backup run log.
pipeline_runs3,098Pipeline execution history.
sync_log2,159General sync operation log.
TableRowsNotes
recipes103Homebrew recipes synced from BrewersFriend.
sessions80Brewing sessions.
TableRowsNotes
ha.events4,118HA state change events. Indexed on (entity_id, event_time DESC).
TableRowsNotes
memories129,738Core memory store. HNSW index on binary_quantize(embedding)::bit(4096) using hamming distance.
entities85Named entities extracted from memories.
entity_relations6Relations between entities.
bridge_sync_log170Sync state between source tables and the memory server.
synthesis_artifacts1Synthesized knowledge artifacts.

All 4 tables are empty and isolated. Accessible only to the dedicated therapy role. No remote or app role access. No cross-schema views include this schema.

Table
therapy.sessions
therapy.session_themes
therapy.action_items
therapy.medication_changes

all_messages — The Canonical Messaging View

Section titled “all_messages — The Canonical Messaging View”

The most important view in the schema. A UNION of messages, social_messages (non-Discord), and discord_messages. All cross-platform analytics must use this view — never query the source tables directly.

Provides: id, contact_id, direction (‘inbound’/‘outbound’), timestamp, content, platform, source_table, source_id. Filters to rows where contact_id IS NOT NULL (linked messages only). Discord direction is resolved via system state for Chris’s own user ID.

ViewPurpose
config_registry_current_v1Current Manifest state per config item. Four states: in_sync, drift, stale, unknown.
config_registry_prompt_snapshot_v1Manifest snapshot formatted for LLM prompt injection.
calendar_events_activeNon-excluded calendar events only.
health_records_activeNon-excluded health records only.
contact_communication_overviewAggregated communication stats per contact across all sources.
data_freshnessFreshness status across all tracked pipeline sources.
relationship_health_summaryRelationship analytics from cadence stats and scores.
time_blocks_dailyDaily aggregates of Time Portrait blocks.
memory.belief_evolutionHow beliefs and claims have changed over time.
memory.vw_bridge_sync_statusOverall memory bridge sync status.

RolePurpose
superuserSuperuser / DBA. Never used for application queries.
appPrimary application role. INSERT/UPDATE/SELECT on all non-therapy tables.
readonlyRead-only access for reporting and staging queries.
remote_rwRemote write access via MCP proxy. No DELETE, no DDL. Does not have INSERT on some tables (e.g., document_versions).
n8n_rolen8n workflow engine access.
ha_roleHome Assistant access (ha.* schema only).
grafana_roleGrafana read-only monitoring.
authelia_roleAuthelia SSO session store.
therapy_appIsolated therapy schema access. Only role that can read or write therapy.*.

Rule: Use the app role for all application code. Never use the superuser role for queries.


All time handling follows a single source-of-truth rule. Violating this causes silent off-by-one-day bugs at Pacific midnight.

Column typeFunction to use
TIMESTAMPTZNOW()
TIMESTAMP (no tz)pacific_now()
DATEpacific_today()

Utility functions: pacific_now(), pacific_today(), pacific_date(ts), pacific_timestamp(ts).

Mixed PK strategy (historical artifact from early migrations):

  • TEXT (cast UUID): messages, health_records, contacts, calendar_events — older public tables
  • UUID (gen_random_uuid()): documents, social_messages, discord_messages, transactions, workouts, peak_state_scores, time_blocks, all memory.* tables — newer tables

Most import tables carry a *_hash column with a unique constraint:

  • health_records.record_hash
  • workouts.workout_hash
  • contacts.contact_hash
  • calendar_events: unique on (source, external_id)
  • browser_history: unique on (md5(url), visit_time)

Tables with excluded + excluded_reason: health_records, calendar_events, workouts. Filtered by *_active views. Does not use a deleted_at pattern.

contact_id is the foreign key connecting messages and events to contacts. contact_identifiers provides typed lookup (email, phone, discord_id). contact_aliases handles name variations. The all_messages view only includes rows where contact_id IS NOT NULL.

memory.memories uses 4096-dimension vectors with binary quantization HNSW index (binary_quantize(embedding)::bit(4096), hamming distance). Two-stage retrieval: HNSW for candidate set, exact cosine for reranking. Similarity threshold: 0.45 (migration 301).

messages and calendar_events also carry vector embedding columns for per-row semantic search.

Full-text search: messages, documents, and memory.memories carry tsvector search_vector columns maintained by triggers.

notify_dashboard_event() and related functions use PostgreSQL NOTIFY for real-time SSE streaming to the dashboard. Channels: dashboard_events, dispatch_update, council_update, github_updated, entity_extraction.

config_registry_item defines what to track. config_registry_observation records observed values after inbox processing. config_registry_event_inbox receives raw events. config_registry_compute_state() determines four-state status per item. Views config_registry_current_v1 and config_registry_prompt_snapshot_v1 expose current state for monitoring and LLM injection.


302 migrations applied as of capture date. All migrations are append-only and tracked in schema_migrations.

Rules:

  • Migrations are numbered sequentially after a consolidated baseline (000_, 001_, 002_).
  • No migration may be modified after it is applied. If a change is needed, create a new migration.
  • Multi-statement SQL in n8n Postgres nodes must be wrapped in a function (n8n executes as prepared statements that reject multiple statements).

Key recent migrations:

  • 302: Dropped stale social_messages index
  • 301: knowledge_search default threshold 0.25 -> 0.45
  • 294-297: Time Portrait schema (time_blocks, time_portrait_sources, reconciler tables)
  • 263: knowledge_search function + source_config; CTE fence fix (shared CTE caused HNSW bypass)
  • 261: binary_quantize HNSW index for memory embeddings

FunctionPurpose
pacific_now()Current TIMESTAMP (no tz) in Pacific time
pacific_today()Current DATE in Pacific time
pacific_date(ts)Converts TIMESTAMPTZ to Pacific DATE
pacific_timestamp(ts)Converts TIMESTAMPTZ to Pacific TIMESTAMP
FunctionPurpose
memory.knowledge_search(...)14-param semantic + FTS search over memories. Two-stage HNSW retrieval. Default threshold 0.45.
memory.entity_search(...)Entity-focused semantic search
memory.hybrid_search(...)Combined vector + FTS search
search_dialogue(...)FTS search over dialogue table
FunctionPurpose
refresh_relationship_scores()Recomputes all relationship scores
relationship_briefing_data(contact_id)Rich relationship summary for a contact
relationships_needing_attention()Contacts with drifting cadence
inner_circle()High-tier relationship contacts
FunctionPurpose
calculate_peak_state_score(date)Computes Peak State score for a date
refresh_activity_timeline()Refreshes the activity_timeline materialized view
day_timeline(date)Full activity timeline for a specific day
check_data_freshness()Returns freshness status for all tracked sources
FunctionPurpose
notify_dashboard_event(channel, payload)PostgreSQL NOTIFY for dashboard SSE
notify_dispatch_update(...)Notifies dispatch update channel
archive_document_version()Trigger: archives document to document_versions on UPDATE