[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6NWR4HHSFR0VR5EXFRWA747":3,"skill-same:01M6NWR4HHSFR0VR5EXFRWA747":64},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":37,"linkOnly":38,"markdownContent":39,"markdownBody":40,"frontMatter":41,"refName":42,"commitSha":43,"skillDirectory":44,"forksCount":14,"repositoryHtmlUrl":45,"repositoryHomepageUrl":6,"ownerHtmlUrl":46,"ownerBlogUrl":47,"ownerDescription":48,"updatedAt":49,"install":50,"resources":63},"01M6NWR4HHSFR0VR5EXFRWA747","vector-db-patterns",null,"Embedding strategies, ANN algorithms, hybrid search, RAG chunking strategies, and reranking for semantic search and retrieval.","rubicanjr\u002FFinCognis","rubicanjr","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F234912519?v=4","01M6NT156NND8J474G34SB3923","Rubi","01M6NT15B70RWXE1N3YV0BZY8A",0,"MIT","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvector-db-patterns\u002Fskill.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36],"db","vector db patterns","vector db","patterns","vector","embedding strategies","algorithms","strategies","chunking","rag","semantic","retrieval","embedding","Hybrid Search","search","for","hybrid","semantic search","2026-11-10 10:12:30",false,"---\nname: vector-db-patterns\ndescription: Embedding strategies, ANN algorithms, hybrid search, RAG chunking strategies, and reranking for semantic search and retrieval.\n---\n\n# Vector DB Patterns\n\nSemantic search and retrieval-augmented generation (RAG) patterns with vector databases.\n\n## Embedding Strategies\n\n```typescript\nimport { OpenAI } from 'openai'\n\nconst openai = new OpenAI()\n\n\u002F\u002F Batch embedding for efficiency (max 2048 inputs per request for text-embedding-3-small)\nasync function embedTexts(texts: string[]): Promise\u003Cnumber[][]> {\n  const BATCH_SIZE = 2048\n  const allEmbeddings: number[][] = []\n\n  for (let i = 0; i \u003C texts.length; i += BATCH_SIZE) {\n    const batch = texts.slice(i, i + BATCH_SIZE)\n    const response = await openai.embeddings.create({\n      model: 'text-embedding-3-small',  \u002F\u002F 1536 dimensions, good cost\u002Fquality\n      input: batch,\n      dimensions: 512,                  \u002F\u002F Reduce dims for speed (Matryoshka)\n    })\n    allEmbeddings.push(...response.data.map(d => d.embedding))\n  }\n\n  return allEmbeddings\n}\n\n\u002F\u002F Embed with prefix for asymmetric retrieval\nasync function embedForSearch(query: string): Promise\u003Cnumber[]> {\n  const [embedding] = await embedTexts([`search_query: ${query}`])\n  return embedding\n}\n\nasync function embedForStorage(document: string): Promise\u003Cnumber[]> {\n  const [embedding] = await embedTexts([`search_document: ${document}`])\n  return embedding\n}\n```\n\n## Chunking Strategies for RAG\n\n```typescript\ninterface Chunk {\n  id: string\n  text: string\n  metadata: {\n    sourceId: string\n    chunkIndex: number\n    startChar: number\n    endChar: number\n  }\n}\n\n\u002F\u002F Recursive character splitting with overlap\nfunction chunkText(\n  text: string,\n  chunkSize: number = 512,\n  overlap: number = 50\n): Chunk[] {\n  const separators = ['\\n\\n', '\\n', '. ', ' ']\n  return recursiveSplit(text, separators, chunkSize, overlap)\n}\n\nfunction recursiveSplit(\n  text: string,\n  separators: string[],\n  chunkSize: number,\n  overlap: number\n): Chunk[] {\n  if (text.length \u003C= chunkSize) {\n    return [{ id: crypto.randomUUID(), text, metadata: {} as any }]\n  }\n\n  const separator = separators.find(s => text.includes(s)) ?? ''\n  const parts = text.split(separator)\n  const chunks: Chunk[] = []\n  let current = ''\n\n  for (const part of parts) {\n    const candidate = current ? current + separator + part : part\n    if (candidate.length > chunkSize && current) {\n      chunks.push({ id: crypto.randomUUID(), text: current.trim(), metadata: {} as any })\n      \u002F\u002F Overlap: keep last N chars of previous chunk\n      const overlapText = current.slice(-overlap)\n      current = overlapText + separator + part\n    } else {\n      current = candidate\n    }\n  }\n  if (current.trim()) {\n    chunks.push({ id: crypto.randomUUID(), text: current.trim(), metadata: {} as any })\n  }\n\n  return chunks\n}\n\n\u002F\u002F Semantic chunking: split at topic boundaries using embeddings\nasync function semanticChunk(text: string, threshold: number = 0.3): Promise\u003CChunk[]> {\n  const sentences = text.match(\u002F[^.!?]+[.!?]+\u002Fg) ?? [text]\n  const embeddings = await embedTexts(sentences)\n  const chunks: string[][] = [[sentences[0]]]\n\n  for (let i = 1; i \u003C sentences.length; i++) {\n    const similarity = cosineSimilarity(embeddings[i - 1], embeddings[i])\n    if (similarity \u003C threshold) {\n      \u002F\u002F Low similarity = topic boundary = new chunk\n      chunks.push([sentences[i]])\n    } else {\n      chunks[chunks.length - 1].push(sentences[i])\n    }\n  }\n\n  return chunks.map((sentences, i) => ({\n    id: crypto.randomUUID(),\n    text: sentences.join(' ').trim(),\n    metadata: { sourceId: '', chunkIndex: i, startChar: 0, endChar: 0 }\n  }))\n}\n```\n\n## Vector Search with Metadata Filtering\n\n```typescript\n\u002F\u002F Using Pinecone\nimport { Pinecone } from '@pinecone-database\u002Fpinecone'\n\nconst pinecone = new Pinecone()\nconst index = pinecone.index('documents')\n\n\u002F\u002F Upsert with metadata\nasync function indexDocument(doc: Document, chunks: Chunk[]): Promise\u003Cvoid> {\n  const embeddings = await embedTexts(chunks.map(c => c.text))\n\n  const vectors = chunks.map((chunk, i) => ({\n    id: chunk.id,\n    values: embeddings[i],\n    metadata: {\n      text: chunk.text,\n      sourceId: doc.id,\n      sourceTitle: doc.title,\n      category: doc.category,\n      createdAt: doc.createdAt.toISOString(),\n      chunkIndex: i,\n    }\n  }))\n\n  \u002F\u002F Upsert in batches of 100\n  for (let i = 0; i \u003C vectors.length; i += 100) {\n    await index.upsert(vectors.slice(i, i + 100))\n  }\n}\n\n\u002F\u002F Query with metadata filter\nasync function searchDocuments(\n  query: string,\n  filters?: { category?: string; after?: Date },\n  topK: number = 10\n): Promise\u003CSearchResult[]> {\n  const queryEmbedding = await embedForSearch(query)\n\n  const filter: Record\u003Cstring, any> = {}\n  if (filters?.category) {\n    filter.category = { $eq: filters.category }\n  }\n  if (filters?.after) {\n    filter.createdAt = { $gte: filters.after.toISOString() }\n  }\n\n  const results = await index.query({\n    vector: queryEmbedding,\n    topK,\n    includeMetadata: true,\n    filter: Object.keys(filter).length > 0 ? filter : undefined,\n  })\n\n  return results.matches.map(m => ({\n    id: m.id,\n    score: m.score ?? 0,\n    text: m.metadata?.text as string,\n    sourceId: m.metadata?.sourceId as string,\n    sourceTitle: m.metadata?.sourceTitle as string,\n  }))\n}\n```\n\n## Hybrid Search (Vector + Keyword)\n\n```typescript\n\u002F\u002F Combine vector similarity with BM25 keyword matching\nasync function hybridSearch(\n  query: string,\n  topK: number = 10,\n  alpha: number = 0.7  \u002F\u002F 0.7 = 70% semantic, 30% keyword\n): Promise\u003CSearchResult[]> {\n  \u002F\u002F Run both searches in parallel\n  const [vectorResults, keywordResults] = await Promise.all([\n    vectorSearch(query, topK * 2),\n    keywordSearch(query, topK * 2),  \u002F\u002F BM25 via Elasticsearch\n  ])\n\n  \u002F\u002F Reciprocal Rank Fusion (RRF)\n  const k = 60  \u002F\u002F RRF constant\n  const scores = new Map\u003Cstring, number>()\n\n  vectorResults.forEach((r, rank) => {\n    const current = scores.get(r.id) ?? 0\n    scores.set(r.id, current + alpha * (1 \u002F (k + rank + 1)))\n  })\n\n  keywordResults.forEach((r, rank) => {\n    const current = scores.get(r.id) ?? 0\n    scores.set(r.id, current + (1 - alpha) * (1 \u002F (k + rank + 1)))\n  })\n\n  \u002F\u002F Sort by combined score, return top K\n  const allResults = [...vectorResults, ...keywordResults]\n  const uniqueResults = new Map(allResults.map(r => [r.id, r]))\n\n  return [...scores.entries()]\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, topK)\n    .map(([id, score]) => ({\n      ...uniqueResults.get(id)!,\n      score,\n    }))\n}\n```\n\n## Reranking\n\n```typescript\n\u002F\u002F Cross-encoder reranking: slower but much more accurate than bi-encoder\nasync function rerankResults(\n  query: string,\n  results: SearchResult[],\n  topK: number = 5\n): Promise\u003CSearchResult[]> {\n  \u002F\u002F Use Cohere Rerank or cross-encoder model\n  const response = await fetch('https:\u002F\u002Fapi.cohere.ai\u002Fv1\u002Frerank', {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${process.env.COHERE_API_KEY}`,\n      'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify({\n      model: 'rerank-english-v3.0',\n      query,\n      documents: results.map(r => r.text),\n      top_n: topK,\n      return_documents: false,\n    }),\n  })\n\n  const data = await response.json()\n\n  return data.results.map((r: any) => ({\n    ...results[r.index],\n    score: r.relevance_score,\n  }))\n}\n\n\u002F\u002F RAG pipeline: retrieve → rerank → generate\nasync function ragQuery(query: string): Promise\u003Cstring> {\n  \u002F\u002F Step 1: Retrieve candidates (broad, fast)\n  const candidates = await hybridSearch(query, 20)\n\n  \u002F\u002F Step 2: Rerank (narrow, accurate)\n  const reranked = await rerankResults(query, candidates, 5)\n\n  \u002F\u002F Step 3: Generate answer with context\n  const context = reranked.map(r => r.text).join('\\n\\n')\n  const response = await openai.chat.completions.create({\n    model: 'gpt-4o',\n    messages: [\n      { role: 'system', content: `Answer based on the context below.\\n\\nContext:\\n${context}` },\n      { role: 'user', content: query },\n    ],\n  })\n\n  return response.choices[0].message.content!\n}\n```\n\n## Checklist\n\n- [ ] Chunk size 256-1024 tokens with 10-20% overlap\n- [ ] Asymmetric embedding prefixes for query vs document\n- [ ] Metadata stored alongside vectors for pre-filtering\n- [ ] Hybrid search (vector + BM25) for best recall\n- [ ] Reranking top-N candidates with cross-encoder\n- [ ] Batch embedding calls (never one-by-one)\n- [ ] Dimension reduction (Matryoshka) for cost\u002Fspeed optimization\n- [ ] Evaluation: hit rate, MRR, NDCG on test queries\n\n## Anti-Patterns\n\n- Embedding entire documents as single vectors (context lost, poor retrieval)\n- Fixed-size chunking ignoring sentence\u002Fparagraph boundaries\n- Only vector search without keyword fallback (misses exact matches)\n- Embedding queries and documents identically (asymmetric retrieval needs prefixes)\n- Not evaluating retrieval quality (building blind)\n- Storing embeddings without source text (can't debug or rerank)\n","# Vector DB Patterns\n\nSemantic search and retrieval-augmented generation (RAG) patterns with vector databases.\n\n## Embedding Strategies\n\n```typescript\nimport { OpenAI } from 'openai'\n\nconst openai = new OpenAI()\n\n\u002F\u002F Batch embedding for efficiency (max 2048 inputs per request for text-embedding-3-small)\nasync function embedTexts(texts: string[]): Promise\u003Cnumber[][]> {\n  const BATCH_SIZE = 2048\n  const allEmbeddings: number[][] = []\n\n  for (let i = 0; i \u003C texts.length; i += BATCH_SIZE) {\n    const batch = texts.slice(i, i + BATCH_SIZE)\n    const response = await openai.embeddings.create({\n      model: 'text-embedding-3-small',  \u002F\u002F 1536 dimensions, good cost\u002Fquality\n      input: batch,\n      dimensions: 512,                  \u002F\u002F Reduce dims for speed (Matryoshka)\n    })\n    allEmbeddings.push(...response.data.map(d => d.embedding))\n  }\n\n  return allEmbeddings\n}\n\n\u002F\u002F Embed with prefix for asymmetric retrieval\nasync function embedForSearch(query: string): Promise\u003Cnumber[]> {\n  const [embedding] = await embedTexts([`search_query: ${query}`])\n  return embedding\n}\n\nasync function embedForStorage(document: string): Promise\u003Cnumber[]> {\n  const [embedding] = await embedTexts([`search_document: ${document}`])\n  return embedding\n}\n```\n\n## Chunking Strategies for RAG\n\n```typescript\ninterface Chunk {\n  id: string\n  text: string\n  metadata: {\n    sourceId: string\n    chunkIndex: number\n    startChar: number\n    endChar: number\n  }\n}\n\n\u002F\u002F Recursive character splitting with overlap\nfunction chunkText(\n  text: string,\n  chunkSize: number = 512,\n  overlap: number = 50\n): Chunk[] {\n  const separators = ['\\n\\n', '\\n', '. ', ' ']\n  return recursiveSplit(text, separators, chunkSize, overlap)\n}\n\nfunction recursiveSplit(\n  text: string,\n  separators: string[],\n  chunkSize: number,\n  overlap: number\n): Chunk[] {\n  if (text.length \u003C= chunkSize) {\n    return [{ id: crypto.randomUUID(), text, metadata: {} as any }]\n  }\n\n  const separator = separators.find(s => text.includes(s)) ?? ''\n  const parts = text.split(separator)\n  const chunks: Chunk[] = []\n  let current = ''\n\n  for (const part of parts) {\n    const candidate = current ? current + separator + part : part\n    if (candidate.length > chunkSize && current) {\n      chunks.push({ id: crypto.randomUUID(), text: current.trim(), metadata: {} as any })\n      \u002F\u002F Overlap: keep last N chars of previous chunk\n      const overlapText = current.slice(-overlap)\n      current = overlapText + separator + part\n    } else {\n      current = candidate\n    }\n  }\n  if (current.trim()) {\n    chunks.push({ id: crypto.randomUUID(), text: current.trim(), metadata: {} as any })\n  }\n\n  return chunks\n}\n\n\u002F\u002F Semantic chunking: split at topic boundaries using embeddings\nasync function semanticChunk(text: string, threshold: number = 0.3): Promise\u003CChunk[]> {\n  const sentences = text.match(\u002F[^.!?]+[.!?]+\u002Fg) ?? [text]\n  const embeddings = await embedTexts(sentences)\n  const chunks: string[][] = [[sentences[0]]]\n\n  for (let i = 1; i \u003C sentences.length; i++) {\n    const similarity = cosineSimilarity(embeddings[i - 1], embeddings[i])\n    if (similarity \u003C threshold) {\n      \u002F\u002F Low similarity = topic boundary = new chunk\n      chunks.push([sentences[i]])\n    } else {\n      chunks[chunks.length - 1].push(sentences[i])\n    }\n  }\n\n  return chunks.map((sentences, i) => ({\n    id: crypto.randomUUID(),\n    text: sentences.join(' ').trim(),\n    metadata: { sourceId: '', chunkIndex: i, startChar: 0, endChar: 0 }\n  }))\n}\n```\n\n## Vector Search with Metadata Filtering\n\n```typescript\n\u002F\u002F Using Pinecone\nimport { Pinecone } from '@pinecone-database\u002Fpinecone'\n\nconst pinecone = new Pinecone()\nconst index = pinecone.index('documents')\n\n\u002F\u002F Upsert with metadata\nasync function indexDocument(doc: Document, chunks: Chunk[]): Promise\u003Cvoid> {\n  const embeddings = await embedTexts(chunks.map(c => c.text))\n\n  const vectors = chunks.map((chunk, i) => ({\n    id: chunk.id,\n    values: embeddings[i],\n    metadata: {\n      text: chunk.text,\n      sourceId: doc.id,\n      sourceTitle: doc.title,\n      category: doc.category,\n      createdAt: doc.createdAt.toISOString(),\n      chunkIndex: i,\n    }\n  }))\n\n  \u002F\u002F Upsert in batches of 100\n  for (let i = 0; i \u003C vectors.length; i += 100) {\n    await index.upsert(vectors.slice(i, i + 100))\n  }\n}\n\n\u002F\u002F Query with metadata filter\nasync function searchDocuments(\n  query: string,\n  filters?: { category?: string; after?: Date },\n  topK: number = 10\n): Promise\u003CSearchResult[]> {\n  const queryEmbedding = await embedForSearch(query)\n\n  const filter: Record\u003Cstring, any> = {}\n  if (filters?.category) {\n    filter.category = { $eq: filters.category }\n  }\n  if (filters?.after) {\n    filter.createdAt = { $gte: filters.after.toISOString() }\n  }\n\n  const results = await index.query({\n    vector: queryEmbedding,\n    topK,\n    includeMetadata: true,\n    filter: Object.keys(filter).length > 0 ? filter : undefined,\n  })\n\n  return results.matches.map(m => ({\n    id: m.id,\n    score: m.score ?? 0,\n    text: m.metadata?.text as string,\n    sourceId: m.metadata?.sourceId as string,\n    sourceTitle: m.metadata?.sourceTitle as string,\n  }))\n}\n```\n\n## Hybrid Search (Vector + Keyword)\n\n```typescript\n\u002F\u002F Combine vector similarity with BM25 keyword matching\nasync function hybridSearch(\n  query: string,\n  topK: number = 10,\n  alpha: number = 0.7  \u002F\u002F 0.7 = 70% semantic, 30% keyword\n): Promise\u003CSearchResult[]> {\n  \u002F\u002F Run both searches in parallel\n  const [vectorResults, keywordResults] = await Promise.all([\n    vectorSearch(query, topK * 2),\n    keywordSearch(query, topK * 2),  \u002F\u002F BM25 via Elasticsearch\n  ])\n\n  \u002F\u002F Reciprocal Rank Fusion (RRF)\n  const k = 60  \u002F\u002F RRF constant\n  const scores = new Map\u003Cstring, number>()\n\n  vectorResults.forEach((r, rank) => {\n    const current = scores.get(r.id) ?? 0\n    scores.set(r.id, current + alpha * (1 \u002F (k + rank + 1)))\n  })\n\n  keywordResults.forEach((r, rank) => {\n    const current = scores.get(r.id) ?? 0\n    scores.set(r.id, current + (1 - alpha) * (1 \u002F (k + rank + 1)))\n  })\n\n  \u002F\u002F Sort by combined score, return top K\n  const allResults = [...vectorResults, ...keywordResults]\n  const uniqueResults = new Map(allResults.map(r => [r.id, r]))\n\n  return [...scores.entries()]\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, topK)\n    .map(([id, score]) => ({\n      ...uniqueResults.get(id)!,\n      score,\n    }))\n}\n```\n\n## Reranking\n\n```typescript\n\u002F\u002F Cross-encoder reranking: slower but much more accurate than bi-encoder\nasync function rerankResults(\n  query: string,\n  results: SearchResult[],\n  topK: number = 5\n): Promise\u003CSearchResult[]> {\n  \u002F\u002F Use Cohere Rerank or cross-encoder model\n  const response = await fetch('https:\u002F\u002Fapi.cohere.ai\u002Fv1\u002Frerank', {\n    method: 'POST',\n    headers: {\n      Authorization: `Bearer ${process.env.COHERE_API_KEY}`,\n      'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify({\n      model: 'rerank-english-v3.0',\n      query,\n      documents: results.map(r => r.text),\n      top_n: topK,\n      return_documents: false,\n    }),\n  })\n\n  const data = await response.json()\n\n  return data.results.map((r: any) => ({\n    ...results[r.index],\n    score: r.relevance_score,\n  }))\n}\n\n\u002F\u002F RAG pipeline: retrieve → rerank → generate\nasync function ragQuery(query: string): Promise\u003Cstring> {\n  \u002F\u002F Step 1: Retrieve candidates (broad, fast)\n  const candidates = await hybridSearch(query, 20)\n\n  \u002F\u002F Step 2: Rerank (narrow, accurate)\n  const reranked = await rerankResults(query, candidates, 5)\n\n  \u002F\u002F Step 3: Generate answer with context\n  const context = reranked.map(r => r.text).join('\\n\\n')\n  const response = await openai.chat.completions.create({\n    model: 'gpt-4o',\n    messages: [\n      { role: 'system', content: `Answer based on the context below.\\n\\nContext:\\n${context}` },\n      { role: 'user', content: query },\n    ],\n  })\n\n  return response.choices[0].message.content!\n}\n```\n\n## Checklist\n\n- [ ] Chunk size 256-1024 tokens with 10-20% overlap\n- [ ] Asymmetric embedding prefixes for query vs document\n- [ ] Metadata stored alongside vectors for pre-filtering\n- [ ] Hybrid search (vector + BM25) for best recall\n- [ ] Reranking top-N candidates with cross-encoder\n- [ ] Batch embedding calls (never one-by-one)\n- [ ] Dimension reduction (Matryoshka) for cost\u002Fspeed optimization\n- [ ] Evaluation: hit rate, MRR, NDCG on test queries\n\n## Anti-Patterns\n\n- Embedding entire documents as single vectors (context lost, poor retrieval)\n- Fixed-size chunking ignoring sentence\u002Fparagraph boundaries\n- Only vector search without keyword fallback (misses exact matches)\n- Embedding queries and documents identically (asymmetric retrieval needs prefixes)\n- Not evaluating retrieval quality (building blind)\n- Storing embeddings without source text (can't debug or rerank)\n",{"name":5,"description":7},"main","70e1c350500ee750987420bbae48837afa906b7e","skills\u002Fvector-db-patterns","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis","https:\u002F\u002Fgithub.com\u002Frubicanjr","linktr.ee\u002Ffinanskodu","Industrial Engineer & CIO @FinansKodu. Architecting AI-driven financial agents and autonomous workflows. 🏗️ Building systems, not just prompts.","2026-06-09 13:50:15",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add rubicanjr\u002FFinCognis --skill vector-db-patterns",{"tool":56,"command":57},"bunx","bunx skills add rubicanjr\u002FFinCognis --skill vector-db-patterns",{"tool":59,"command":60},"pnpm","pnpm dlx skills add rubicanjr\u002FFinCognis --skill vector-db-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvector-db-patterns\u002Fskill.md",true,[],[65,86,95,113,142,161],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":69,"categories":70,"keywords":76,"publishedAt":37},"01M6NWS9DAXJTADT4T5MB49X8W","workflow-router","Goal-based workflow orchestration - routes tasks to specialist agents based on user goals","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-router\u002FSKILL.md",[71],{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[77,78,79,80,81,82,83,84,85],"workflow router","workflow","router","orchestration","tasks","workflow orchestration","user","goal","goals",{"skillNo":87,"name":88,"nameZh":6,"description":89,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":90,"categories":91,"keywords":92,"publishedAt":37},"01M6NWS3RETSC0SHP16HP66E14","wiring","Wiring Verification","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fwiring\u002FSKILL.md",[],[88,93,94],"verification","false",{"skillNo":96,"name":97,"nameZh":6,"description":98,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":104,"publishedAt":37},"01M6NWS0XW9CVQZBDA1EGW0TWC","websocket-patterns","Connection management, room patterns, reconnection strategies, message buffering, and binary protocol design.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fwebsocket-patterns\u002Fskill.md",[101],{"categoryNo":102,"categoryName":103,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000015","视觉设计",[105,22,106,107,108,109,110,26,111,112],"websocket","websocket patterns","design","protocol","management","message","binary","connection",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":123,"publishedAt":37},"01M6NWRDQDX9ZNETAWRRMQWV52","visual-verdict","Screenshot comparison QA for frontend development. Takes a screenshot of the current implementation, scores it across multiple visual dimensions, and returns a structured PASS\u002FREVISE\u002FFAIL verdict with concrete fixes. Use when implementing UI from a design reference or verifying visual correctness.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-verdict\u002FSKILL.md",[119,122],{"categoryNo":120,"categoryName":121,"taxonomyType":74,"taxonomyTypeDesc":75},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":72,"categoryName":73,"taxonomyType":74,"taxonomyTypeDesc":75},[124,125,126,127,128,129,130,131,34,132,133,134,135,136,137,138,139,107,140,141],"visual verdict","verdict","visual","comparison","correctness","revise","across","implementing","fixes","dimensions","screenshot","frontend development","returns","ui","qa","development","frontend","use",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":148,"publishedAt":37},"01M6NWR8HSNRS7MNDK2J02QYMN","verification-loop","Comprehensive verification system covering build, types, lint, tests, security, and diff review before a PR.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[149,150,93,151,152,153,154,155,156,157,158,159,160],"verification loop","loop","review","diff review","types","tests","build","diff","system","lint","pr","security",{"skillNo":162,"name":163,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":165,"categories":166,"keywords":167,"publishedAt":37},"01M6NWQFTGW6RQQRPQ4Z2XM2BK","variant-analysis","Find similar vulnerabilities across a codebase after discovering one instance. Uses pattern matching, AST search, Semgrep\u002FCodeQL queries, and manual tracing to propagate findings. Adapted from Trail of Bits. Use after finding a bug to check if the same pattern exists elsewhere.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvariant-analysis\u002FSKILL.md",[],[168,169,170,171,172,173,174,175,176,130,177,178,141,179,180,181,182,183,184,33],"variant","variant analysis","analysis","bug","codebase","manual","pattern matching","propagate","matching","pattern","queries","check","find","ast","semgrep","codeql","tracing"]