How the Mímir agent runs in production today, what a "face" is, and the staged buildout that takes the platform from a single shared backend to per-user, per-context faces — plus the forecast personas planned on top of it.
Prod live · Slack Socket Mode First face iteration on viska.gg T12 personas in-flight Per-user tenancy: fast-follow
1 · Current Deployment
A single Node.js host on Railway serves both surfaces — Slack (Socket Mode) and the viska.gg web edge — over one Mastra agent backed by Postgres conversation memory and a Supabase pgvector corpus.
Surfaces / Edge
Slack — Viska CapitalSocket Mode · app_mention, IM, App Home
viska.gg web edgeViskaFront · route → face · Bearer MIMIR_API_SECRET
face = f(route / page context), derived at the edge from a verified session. One backend, but each page context drives its own instructions(face) — the same user gets an analyst posture on a research page and an orientation posture on the homepage, with conversation carried over from Slack.
First iteration — deployed & responding on the viska.gg homepage
The web-home face is live: the homepage routes a verified visitor through the edge into the shared Mímir backend, the host validates the face, injects the homepage instruction posture, and streams a response — carrying over any prior Slack/web conversation for the mapped user. Behaving as expected.
operator-confirmed 2026-06-27 · v1 scope = face-chat only (no new per-user write surface) · per-user write tenancy is fast-follow (§4)
v1 request contract — edge → host
POST /api/chat // SSE, Bearer MIMIR_API_SECRET
{
"message": string, // required"userId": string, // verified id / email"threadId": string, // optional"role": "client", // operator via edge only"face": string // route-derived, NEW
}
Face taxonomy — starter set (extensible)
face
context
web-home
landing / overview
LIVE
web-research
research / corpus
planned
web-portfolio
holdings / positions
planned
default
unmapped fallback
LIVE
Honest status: v1 is intentionally scoped to face-chat. The data path is still shared service-key; per-user write isolation (JWT-consume, tenancy tables, dead-layer purge) is the staged buildout below — not yet in production.
3 · Buildout Roadmap — G1 → G6
The path from "shared backend with face-chat" to "per-user, per-face, zero-bleed." Ordered by gating dependency; ownership split across three repos.
live / shipped in-flight planned
v1Face-chat on viska.gg (web-home)LIVEViskaFront · ViskaMimir
Edge derives face from route, host validates + injects instruction + falls back to default. Conversation carry-over verified.
G2Request-scoped client factoryplannedViskaMimir
Replace 17 inline service-key clients with one central factory. Prereq for G1 — without it, the JWT-consume is 17 divergent edits.
G1Consume the face JWT (no-bleed gate)plannedViskaMimir
JWT is already minted (ES256, S5/PR#38) but never consumed — shard jurisdiction is metadata enforced nowhere. Wire Lane-A per-user writes to build from the per-request user JWT.
G3Split service-key into three lanesplannedViskaMimir
Lane A per-user writes (5 sites) → user JWT · Lane B shared corpus (7) → restricted read role · Lane C system (5) → narrow service role off the request path.
G4Per-user doc / artifact tenancyplannedViskaDB
New tenancy tables with RLS default-deny auth.uid() = user_id, consumed via G1's JWT client. Lets users build own docs/reports with zero cross-user bleed.
Unmapped portal users are keyed on mutable email (GDPR/merge hazard). Cut memory resourceId over to a stable user id; keep email lookup only for carry-over.
G6Purge dead memory layersplannedViskaMimir
Stop writing the write-only pgvector mimir_conversation_memory (rot); retire the host-files web memory (shared-host files = bleed surface).
4 · Forecast Personas — planned deployment
On top of the face layer, T12 deploys distinct forecast personas behind POST /mimir/forecast. Each persona pre-declares the variables it watches — so the same event hitting two personas cannot honestly cite the same drivers, forcing genuine lens divergence. Model: claude-haiku-4-5, temperature 0.
Faces and personas are the same instruction-switching mechanism at different altitudes. The open design question is how they unify before either resumes — to avoid shipping two instruction systems into production at once.
Option 1 recommended
Persona as a dimension inside buildInstructions(face, persona) — one builder, persona threads through runtimeContext.
Option 2
Each persona is its own face + shard set. Rejected — registry sprawl, identical shard sets, wrong altitude.
Option 3
T12 ships standalone, reconcile later at P3. Rejected — guaranteed rework, two systems live simultaneously.
Decision pending: a short design note (builder signature + runtimeContext persona key) reviewed by viska-pm at next-arc planning — before P3 or T12 resumes. Surfaced 2026-06-12.