# RHENIUS — Full LLM & AI Specification > Complete architectural context, authentication flow, API reference, AI action catalogue, grounding > rules and data schemas for Large Language Models and autonomous agents. > Generated from the canonical discovery module (v2.0); regenerate with `npm run discovery:build`. ## 1. What RHENIUS is RHENIUS (internally, Helix) is a private, local-first Personal Relationship Management (PRM) system. It rejects the extractive CRM paradigm: instead of sales pipelines, it models mutual care — reciprocity, favours, debts, gifts, cadence and long-term memory — with cryptographic privacy. - **Architecture**: Local-first client-side storage (IndexedDB / LocalStorage) with optional end-to-end encrypted synchronisation to Supabase PostgreSQL. - **Cryptography**: Argon2id (RFC 9106) key derivation; Paillier additive homomorphic encryption nets reciprocity balances directly over ciphertexts (Enc(a) · Enc(b) = Enc(a+b) mod n²); AES-GCM-256 for records at rest. - **Identity**: Session tokens are 256-bit random values stored server-side as SHA-256 hashes only, presented as Authorization: Bearer or X-Session-Token. Identity is never taken from client-controlled headers. - **AI boundary**: The LLM is an untrusted proposal engine with zero direct database authority: every proposal passes the same validation, ownership and confirmation policy as manual edits, and is audit-logged and reversible. - **Grounding**: Anti-hallucination by construction — only explicitly stated attributes mutate silently; inferred attributes become non-mutating suggestions (4-valued grounding). - **Privacy**: Zero telemetry, zero advertising, no third-party trackers. The people recorded in a user’s network are never exposed to any crawler or anonymous request. ## 2. Identity & authentication (read this before calling the API) 1. `POST /api/auth/login` with `{ email, password }` → `{ success, token, user }`. Passwords are verified with Argon2id (RFC 9106). Accounts lock temporarily after repeated failures; tokens are stored server-side as SHA-256 hashes only. 2. Send the token on every protected call as `Authorization: Bearer ` (preferred) or `X-Session-Token: `. 3. Identity and data scope derive exclusively from the validated session. There is no header or parameter that selects another user's data, and no anonymous read path exists. 4. Sessions expire and can be revoked (`POST /api/auth/logout`); a revoked token returns `401 SESSION_REVOKED` and must be replaced by a fresh login. Error codes an agent should handle: `401 SESSION_REQUIRED` (no token), `401 INVALID_SESSION` (unknown token), `401 SESSION_REVOKED`, `409 VERSION_MISMATCH` (optimistic-locking conflict — re-read the record and retry), `429` (rate limited — back off). ## 3. HTTP API reference ### System #### `GET /api/health` — Liveness probe with the active database provider. - **Auth**: public (no session required) - **Response**: `{ status: "ok", message: string, provider: "supabase" | "d1", authenticated: boolean }` ### Auth #### `POST /api/auth/login` — Exchange email + password (Argon2id verification) for a session token. - **Auth**: public (no session required) - Returns a session token to present as `Authorization: Bearer ` or `X-Session-Token: ` on every protected call. Tokens are stored server-side as SHA-256 hashes only; failed attempts are rate-limited with account lockout. - **Request**: `{ email: string, password: string }` - **Response**: `{ success: true, token: string, user: { id: string, email: string } }` #### `POST /api/auth/signup` — Create an account and receive a session token. - **Auth**: public (no session required) - **Request**: `{ email: string, password: string, name?: string }` - **Response**: `{ success: true, token: string, user: { id: string, email: string } }` #### `POST /api/auth/logout` — Revoke the presented session token. - **Auth**: public (no session required) - **Request**: `{ token?: string }` - **Response**: `{ success: true }` #### `GET /api/auth/me` — Resolve the presented session token to its account. - **Auth**: public (no session required) - **Response**: `{ authenticated: boolean, email?: string, userId?: string }` ### Contacts #### `GET /api/contacts` — List the authenticated user’s contacts. - **Auth**: session token required - **Response**: `Contact[]` #### `POST /api/contacts` — Create one contact. - **Auth**: session token required - **Request**: `Partial & { name: string }` - **Response**: `{ success: true, id: string } & Contact` #### `POST /api/contacts/batch` — Upsert many contacts (vCard / bulk import). - **Auth**: session token required - **Request**: `{ contacts: Array & { name: string }> }` - **Response**: `{ success: true, importedCount: number, updatedCount: number }` #### `POST /api/contacts/batch-update` — Apply one field change (tags, cadence, group) to many contacts. - **Auth**: session token required - **Request**: `{ contactIds: string[], patch: object }` - **Response**: `{ success: true, updatedCount: number }` #### `POST /api/contacts/batch-delete` — Delete many contacts with undo snapshots. - **Auth**: session token required - **Request**: `{ contactIds: string[] }` - **Response**: `{ success: true, deletedCount: number }` ### Data #### `GET /api/data` — Full app state: contacts, smart lists, entities and journal pages. - **Auth**: session token required - **Response**: `{ contacts: Contact[], logs: unknown[], smartLists: Array<{ id, name, query, contactIds }>, entities: Entity[], journalPages: JournalPage[] }` #### `GET /api/export` — Complete portable export of the account. - **Auth**: session token required - **Response**: `{ contacts, entities, smartLists, journalPages, familyTree, exportedAt: string, version: "1.0" }` ### Family Tree #### `GET /api/family-tree` — List genealogical family members and pedigree links. - **Auth**: session token required - **Response**: `FamilyMember[]` #### `PUT /api/family-tree` — Replace the family tree (full snapshot write) and sync linked contacts. - **Auth**: session token required - **Request**: `{ members: FamilyMemberInput[] } | FamilyMemberInput[]` - **Response**: `{ success: true, members: FamilyMember[] }` ### Entities #### `GET /api/entities` — List entities — companies, projects and pets with linked members. - **Auth**: session token required - **Response**: `Entity[]` #### `POST /api/entities` — Create an entity. - **Auth**: session token required - **Request**: `{ name: string, type?: "company" | "project" | "pet", description?, members?: string[], … }` - **Response**: `Entity` #### `PUT /api/entities/{id}` — Update an entity. - **Auth**: session token required - **Request**: `Partial` - **Response**: `Entity` #### `DELETE /api/entities/{id}` — Delete an entity. - **Auth**: session token required - **Response**: `{ success: true }` ### Journal #### `GET /api/journal-pages` — List daily journal pages with blocks and linked attendees. - **Auth**: session token required - **Response**: `JournalPage[]` #### `PUT /api/journal-pages` — Upsert journal pages. A full list also deletes pages removed client-side. - **Auth**: session token required - **Request**: `JournalPage[] | { pages: JournalPage[] } | JournalPage` - **Response**: `{ success: true, count: number }` #### `DELETE /api/journal-pages/{id}` — Delete one journal page. - **Auth**: session token required - **Response**: `{ success: true }` ### AI Agent #### `POST /api/action` — Master natural-language relationship-intelligence agent. - **Auth**: session token required - **Headers**: Idempotency-Key (optional; retries never duplicate mutations) - Runs the deterministic fast path first (<5ms, no model call); unhandled prompts escalate to the configured LLM through the 9-stage pipeline (intent → entity resolution → grounding → planner → validator → confirmation policy). Destructive proposals pause at /api/action/confirm. Every action is audit-logged and reversible. - **Request**: `{ text: string, currentContactId?: string, messages?: Array<{ role: "user" | "assistant", content: string }>, model?: string, provider?: string }` - **Response**: `AIResult — { type: "action" | "clarification" | "no_action" | "error", … }` #### `POST /api/action/confirm` — Approve a DESTRUCTIVE proposal created by /api/action. - **Auth**: session token required - Proposals expire after 5 minutes. - **Request**: `{ actionId: string }` - **Response**: `AIResult (type "action" — the executed mutation)` #### `POST /api/action/undo` — Atomically reverse a previously executed mutation. - **Auth**: session token required - **Headers**: Optimistic locking: 409 VERSION_MISMATCH on concurrent modification - Returns HTTP 409 with code VERSION_MISMATCH when the record changed underneath the undo (optimistic locking). - **Request**: `{ mutationId: string, expectedVersion?: number }` - **Response**: `{ type: "action", envelope: { status: "UNDONE", … } }` #### `POST /api/query` — Read-only natural-language question over the network. - **Auth**: session token required - **Request**: `{ query: string }` - **Response**: `{ answer: string, relevantContactIds: string[], suggestedQuestions: string[] }` ### Intelligence #### `POST /api/briefing` — Generate a 1-page pre-meeting executive briefing sheet for a contact. - **Auth**: session token required - **Request**: `{ contact: Contact }` - **Response**: `{ briefing: string, conversationStarters: string[], … }` #### `POST /api/nurture` — Generate outreach, gift and follow-up suggestions for a contact. - **Auth**: session token required - **Request**: `{ contact: Contact }` - **Response**: `{ outreachSuggestions, giftRecommendations, followUpTasks, bestTimeToReach, conversationStarters }` #### `POST /api/ingest-magic` — Parse unstructured text (email signature, bio, notes) into contact fields. - **Auth**: session token required - **Request**: `{ text: string }` - **Response**: `{ contact: Partial, confidence?: object }` ### Ledger #### `POST /api/homomorphic/sum` — Add two Paillier ciphertexts; plaintext values never reach the server. - **Auth**: session token required - **Request**: `{ a: string, b: string, n?: string }` - **Response**: `{ sum: string }` #### `POST /api/homomorphic/network-sum` — Homomorphically aggregate many Paillier ciphertexts across the network. - **Auth**: session token required - **Request**: `{ ciphertexts: string[], n?: string }` - **Response**: `{ sum: string }` ## 4. The AI agent (`POST /api/action`) ### 4.1 Pipeline Natural language is processed through a nine-stage pipeline in which understanding is strictly separated from mutation: intent extraction → entity resolution (with disambiguation — multiple candidates return a clarification question instead of a guess) → context retrieval → four-valued grounding → action planning → deterministic Zod validation → confirmation policy → atomic transaction with undo snapshot → audit log. High-frequency commands run on a deterministic fast path in <5ms without any model call. ### 4.2 Grounding states - **SUPPORTED**: Explicitly stated in the prompt — the only state eligible for silent mutation. - **UNSUPPORTED**: Invented by the model — stripped immediately. - **AMBIGUOUS**: Vague or multiply interpretable — surfaced to the user, never applied silently. - **UNKNOWN**: Not present in the prompt — the field stays empty. ### 4.3 Action catalogue - `CREATE_CONTACT` (safe) : Instantiate a new contact from extracted attributes; unspecified fields stay empty (anti-hallucination). - `UPDATE_CONTACT` (sensitive) : Modify attributes, append verified facts, update cadence or record an interaction; conflicts with existing values surface a warning instead of silently overwriting. - `DELETE_CONTACT` (destructive) : Purge a contact after explicit confirmation; a pre-action snapshot enables single-click undo. - `ADD_NOTE` (safe) : Append a timestamped note to a contact. - `ADD_REMINDER` (safe) : Schedule a follow-up reminder with a due date. - `ADD_DEBT` (sensitive) : Record a debt or favour (direction, amount, description) in the reciprocity ledger. - `ADD_GIFT` (safe) : Log a gift given or received, with price and reaction. - `MANAGE_GIFTS` (safe) : Query or aggregate the gift history. - `QUERY` (safe) : Answer questions over the user’s own network (read-only). - `BATCH_UPDATE` (sensitive) : Apply one change across many contacts atomically. - `COMPOUND_MUTATION` (sensitive) : Decompose a multi-step instruction and execute every step under one shared mutationGroupId for group undo. - `UNDO` (sensitive) : Reverse the previous mutation via its snapshot. ### 4.4 Response envelope Every result is one of: ```typescript type AIResult = | { type: 'action'; envelope: { actionId, mutationId?, status: 'PROPOSED'|'CONFIRMED'|'EXECUTED'|'UNDONE'|'FAILED', actionType, confirmationLevel, proposedChanges, warnings, canUndo, mutationGroupId?, … }, targetContactId?, contact?, decomposedSteps? } | { type: 'clarification'; question: string; candidates: Array<{ id, name, company?, role? }>; originalIntent: string } | { type: 'no_action'; reason: string; explanation: string; answer?: string } | { type: 'error'; code: string; message: string; retryable: boolean; detail?: string }; ``` Destructive (`DESTRUCTIVE`) proposals are returned as `status: 'PROPOSED'` with an `actionId` and expire after 5 minutes; execute them by posting `{ actionId }` to `/api/action/confirm`. Reverse any executed mutation with `/api/action/undo` + `mutationId`. ### 4.5 Agent etiquette (hard invariants) 1. Never invent attribute values. If the user did not state it, the field stays empty. 2. Never treat pronouns or role words ("he", "investor") as names; resolve them to existing contacts or ask for clarification. 3. Carry multi-turn context: pass `messages` so "update him with that info" resolves. 4. Send an `Idempotency-Key` header when retrying `/api/action`; retries never duplicate mutations. 5. Respect the confirmation levels: do not attempt to bypass confirmations for destructive actions. ## 5. Application views The product renders these views inside the sign-in gated single-page shell; none is separately indexable and none appears in the sitemap. - `/` — **Dashboard (Cockpit)**: Network health, morning briefing, cadence alerts, milestone reminders and quick actions. - `/contacts` — **Contacts**: Directory with fuzzy search, multi-tag filtering, custom attributes, briefing sheets and contact cards. - `/graph` — **Relationship Graph**: Interactive 2D/3D force-directed canvas of interpersonal connections and clusters. - `/ledger` — **Reciprocity Ledger**: Paillier-homomorphic ledger of debts, loans, favours and gifts; balances netted in ciphertext space. - `/map` — **World Map**: OpenStreetMap distribution of the network with proximity clustering and travel itinerary planning. - `/journal` — **Journal**: Chronological daily notes with @entity tagging and automatic interaction logging. - `/deals` — **Deals**: Lightweight opportunity pipeline from lead to closed-won. - `/family-tree` — **Family Tree**: Generational pedigree canvas with GEDCOM 5.5 import/export and contact synchronisation. - `/settings` — **Settings**: Master key management, BYOK model configuration, display toggles and data export. ## 6. Data schemas ```typescript interface Contact { id: string; // UUID or slug name: string; // required — never inferred from pronouns or roles role?: string; // job title company?: string; email?: string; phone?: string; location?: string; // only what the user stated — never synthesised country?: string; tier?: 'tier1' | 'tier2' | 'tier3'; frequency?: 'weekly' | 'biweekly' | 'monthly' | 'quarterly' | 'annual'; bio?: string; badges?: string[]; // skills, interests facts?: string[]; // chronological memory anecdotes birthday?: { day?: number | string; month?: number | string; year?: number | string }; relationshipScore?: number; // 0-100, decayed by interaction cadence lastInteractionDate?: string; // ISO timestamp customAttributes?: Array<{ label: string; value: string }>; isFavorite?: boolean; gifts?: GiftItem[]; debts?: DebtItem[]; notes?: Note[]; reminders?: Reminder[]; createdAt: string; // ISO updatedAt?: string; // ISO } interface GiftItem { id: string; type: 'given' | 'received'; description: string; price?: number; currency?: string; date: string; reaction?: string; } interface DebtItem { id: string; direction: 'they_owe' | 'you_owe'; description: string; amount?: number; currency?: string; date: string; resolved: boolean; } ``` ## 7. Cryptographic foundations - **Argon2id** (RFC 9106; 16 MiB memory, 2 iterations) derives the master key client-side; plaintext passwords never reach the server. - **Paillier homomorphic encryption**: reciprocity balances aggregate directly over ciphertexts — `Enc(a) · Enc(b) = Enc(a + b) mod n²` — so the server can compute totals without decrypting. Endpoints: `/api/homomorphic/sum`, `/api/homomorphic/network-sum`. - **AES-GCM-256** encrypts records at rest client-side; the server stores ciphertext. - **Hashed sessions**: session tokens are stored only as SHA-256 digests. ## 8. Discovery resources - `/` : The application shell and sign-in. Public description of the product; all personal data lives behind authentication. - `/privacy` : What is stored, why, who can see it, how long it is kept, and how to exercise data-subject rights. - `/terms` : The contract between the operator and users, including AI output ownership and acceptable use. - `/cookies` : Every browser storage entry with its purpose and lifetime, and how consent is given or withdrawn. - `/crawlers` : Machine-oriented overview of the system: public routes, API surface, and cryptographic invariants for indexers and autonomous agents. - `/llms.txt` : Markdown index for AI crawlers and LLM agents, following the llms.txt specification. - `/openapi.json` : Machine-readable OpenAPI description of the public HTTP API for SDK generation and agent tooling. - `/docs` : Interactive REST API explorer, rate limits matrix, OpenAPI 3.1 specification, and client SDKs.