.claude/skills/matching-engine/SKILL.md
Core matching algorithm using pgvector semantic similarity. Finds "I have, they need" and "I need, they have" connections between users.
npx skillsauth add LilMikey-CN/YHIN matching-engineInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Connect users in two independent directions:
Each direction is scored and displayed independently. There is no combined "bidirectional" score — the two directions are separate sections on the matches page.
All scoring thresholds live in src/lib/constants.ts under MATCH_THRESHOLDS. Never hardcode threshold values elsewhere — always import from constants.
import { MATCH_THRESHOLDS } from '@/lib/constants';
// MATCH_THRESHOLDS.MIN_SCORE — minimum to store a match
// MATCH_THRESHOLDS.STRONG — "strong match" badge
// MATCH_THRESHOLDS.GOOD — "good match" badge
// MATCH_THRESHOLDS.MAX_PER_USER — max matches stored per user
// MATCH_THRESHOLDS.CANDIDATE_POOL — nearest-neighbor candidates per query
These values depend on the embedding model's score distribution. When switching embedding models, recalibrate by:
scripts/recalculate-all-matches.tsconstants.ts so badge tiers produce meaningful separationSee src/server/services/embedding.ts. The embedding provider is configurable (Gemini, OpenAI, mock).
src/server/services/matching.ts uses cosine similarity (1 - (a <=> b)) to find nearest-neighbor resources across users.
For each candidate user, we track the best forward score and best reverse score independently. A match is stored if either direction exceeds MATCH_THRESHOLDS.MIN_SCORE.
Each match inserts TWO rows in a single transaction:
Mirror rows use ON CONFLICT DO UPDATE to handle the case where B already has a row for that pair.
The Prisma schema stores both directions per row:
forwardHave / forwardWant — my HAVE matched their WANTreverseHave / reverseWant — their HAVE matched my WANTA row may have only forward, only reverse, or both populated.
src/server/routers/match.ts — the myMatches endpoint accepts a direction param:
direction: 'forward' → filter by forwardScore >= minScoredirection: 'reverse' → filter by reverseScore >= minScoredirection: undefined → filter by score >= minScore/matches displays two stacked sections (not tabs):
Score badge is displayed on its own row below the resource title.
CREATE INDEX ON resources USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);MATCH_THRESHOLDS from constantsdocumentation
One-time setup that gathers design context for your project and saves it to your AI config file. Run once to establish persistent design guidelines.
data-ai
Prisma ORM patterns including schema design, JSONB fields, pgvector integration, and migration workflow for YHIN
tools
Next.js 15 App Router patterns, server/client components, layouts, and routing conventions for YHIN
testing
Internationalization workflow using next-intl for Chinese/English bilingual support. Read this before adding any user-facing text.