Skip to content

Meshi Platform — System Overview

Meshi Platform — System Overview

Meshi is a people-intelligence platform that builds structured, evolving profiles of individuals from diverse data sources. It provides a backend for portable professional identity, contextual matching, and AI-guided enrichment, built on a trait-claim architecture with explicit trust and provenance at every layer.

Read this document first. It is the mental model you need before any other doc makes sense.


What Meshi does

Meshi takes raw identity signals — LinkedIn profiles, event attendance data, uploaded CSVs, conversation — and converts them into structured, queryable, high-trust profiles. Those profiles feed:

  • Matchmaking: rank members by goal complementarity and value alignment
  • Coach: an AI coach that drives goal-setting and profile refinement
  • Onboarding: a guided kickoff flow that bootstraps a member’s profile on first join
  • Organizer tooling: bulk person import for events, with canonical identity deduplication

The product vision is a professional network where the platform knows enough about each member to make genuinely useful introductions, not just mutual-connection graphs.


Core concepts

Six abstractions underpin everything. Understand these before reading any technical doc.

Entity and Person

An entity is the universal identity root. Every person, organization, or event is an entity first. A person is a typed extension of an entity — it carries factual attributes like display name, role, company, and LinkedIn URL. All other data (traits, evidence, embeddings) hangs off the entity.

Source Records

A source record is an immutable snapshot of raw evidence: a LinkedIn profile as it appeared on a given date, a CSV row from an event import, a manual form submission. Everything in Meshi is traceable back to a source record. Provenance is non-negotiable.

Traits and Claims

A trait is an atomic statement about an entity — a specific skill, value, interest, or characteristic. Traits live in a trait_dimension taxonomy. Each assertion is stored as a trait_claim row with a status state machine — proposed, confirmed, rejected, superseded, archived — defined in packages/domain/src/types.ts (TraitClaimStatus) and governed by packages/domain/src/state-machine.ts. Claims from high-authority sources (e.g. direct user confirmation) override lower-authority inferences. Consumer code uses trust profiles to decide which claims to read, so the same entity can appear differently to a matchmaking engine vs. a public-facing brief.

Goals, Needs, and Offers

Goals are first-class entities representing a member’s professional intent. A goal has a type (e.g. “find a co-founder”, “hire an engineer”) and derives structured Needs and Offers via LLM extraction. Matchmaking scores pairs on how well candidate Offers cover principal Needs and vice versa.

The Brief

The canonical brief is a narrated, synthesized summary of an entity’s profile — it is a derived artifact, not a source of truth. The brief synthesis worker runs after trait inference settles and produces the prose that feeds the coach context, public profile displays, and embedding generation.

The Pipeline

The pipeline is the entity’s progress through enrichment and inference. It is tracked as a state machine on the person_pipeline table whose canonical stage list lives in packages/domain/src/pipeline-stages.ts. Active stages: queued, linkedin_searching, linkedin_matched, linkedin_review, enriching, web_researching, research_review, inferring, synthesizing. Terminal stages: complete, complete_degraded, failed, skipped, unresearchable, inference_failed. The set of allowed transitions is also exported from that module and seeded into a pipeline_allowed_transitions table — a CI test asserts the DB matches the constant exactly. Pipeline transitions use optimistic concurrency (CAS) so concurrent workers don’t clobber each other.


System architecture

Data flows through five layers in sequence. Each layer feeds the next via Inngest events carried through a durable outbox.

┌─────────────────────────────────────────────────────────┐
│ 1. INGESTION │
│ CSV / LinkedIn / form → source_record → entity link │
└────────────────────────┬────────────────────────────────┘
│ LINKEDIN_PROFILE_FETCHED
│ PREFLIGHT_ENRICHMENT_REQUESTED
┌─────────────────────────────────────────────────────────┐
│ 2. ENRICHMENT │
│ Apify scrape → timeline records → text chunks │
│ Deep research → web evidence → source chunks │
└────────────────────────┬────────────────────────────────┘
│ EVIDENCE_ENRICHMENT_COMPLETED
│ ENRICHMENT_COMPLETED
┌─────────────────────────────────────────────────────────┐
│ 3. INFERENCE │
│ Trait inference → trait_claim rows (proposed) │
│ Goal inference → goal rows + needs/offers │
│ Brief synthesis → canonical_brief │
│ Embedding → vector(1024) for ANN search │
└────────────────────────┬────────────────────────────────┘
│ BRIEF_SYNTHESIZED
│ pipeline stage → complete
┌─────────────────────────────────────────────────────────┐
│ 4. FEATURES │
│ Matchmaking (goal-centric ANN + scoring) │
│ Coach runtime (MCP + AI agent loop) │
│ Onboarding kickoff (stations + state machine) │
└─────────────────────────────────────────────────────────┘
At every layer: domain_event_outbox → relay → Inngest
Guarantees at-least-once delivery and replay on failure.

Outbox relay

All material state changes write a row to domain_event_outbox before returning. A background relay process reads undelivered rows and pushes them to Inngest. The outbox is the only place events originate — no fire-and-forget direct Inngest calls. This means any failure can be replayed by re-running the relay.


Key features

FeatureWhat it does
Onboarding (kickoff)Multi-station flow (Portrait → Capabilities → Goals → Read → Pact) that builds a high-trust initial profile from LinkedIn or conversation
MatchmakingScores member pairs by Goal-Complementarity (55%), Value-Alignment (25%), General-Similarity (20%); uses ANN prefiltering with 60s result caching
Deep researchAutonomous web-discovery pipeline that searches, fetches, and evaluates pages to enrich a member’s evidence base
Coach runtimeAI agent loop (TypeScript MCP runtime) connected to Meshi tools; drives goal-setting conversations and profile refinement
Person importBulk-ingest event attendee lists (CSV/LinkedIn) while maintaining canonical entity deduplication across imports

Monorepo layout

PackageWhat it does
packages/domainPure TypeScript domain types, state machines, normalization, trust profiles. Zero internal deps — the leaf everyone else depends on.
packages/dbDatabase connection, all SQL migrations (Kysely), and repository functions. All schema changes go here.
packages/coreBusiness logic service layer — shared by the API, MCP server, and workers. No HTTP, no Inngest.
packages/apiHono HTTP API, Better Auth integration, all routes. Mounts MCP and Inngest handlers at the composition root (main.ts).
packages/workersInngest functions — enrichment, inference, brief synthesis, embedding, outbox relay. All async pipeline logic lives here.
packages/mcpMCP server — tool registrations giving AI agents access to Meshi services over Streamable HTTP.
tools/Developer utilities (Kysely type generation, etc.).

Dependency rule: domaindbcoreapi / workers / mcp. No package may depend on api or workers. Integration tests are the only place cross-package imports are allowed.


Where to go next

GoalRead
Understand the full identity and trust doctrinemeshi-v0.1-spec.md (repo root)
Understand the onboarding flow end-to-endonboarding-flow.md
Understand how matchmaking worksmatchmaking-v0-spec.md
Understand the enrichment/research pipelinedeep-research-pipeline.md
Understand the event architecture (UEG)ueg-agent-ready-events-architecture.md
Deploy or debug the coach runtimecoach-runtime-mcp-deploy.md
Understand repo commands, conventions, testing rulesAGENTS.md (repo root)
Find validated code patternsPATTERNS.md (repo root)