> trieve

Expert guidance for Trieve, the all-in-one search infrastructure that combines full-text, semantic, and hybrid search with built-in RAG capabilities. Helps developers implement production search with chunking, re-ranking, recommendations, and analytics without managing vector databases or embedding models.

fetch
$curl "https://skillshub.wtf/TerminalSkills/skills/trieve?format=md"
SKILL.mdtrieve

Trieve — AI Search Infrastructure

Overview

Trieve, the all-in-one search infrastructure that combines full-text, semantic, and hybrid search with built-in RAG capabilities. Helps developers implement production search with chunking, re-ranking, recommendations, and analytics without managing vector databases or embedding models.

Instructions

Dataset and Chunk Management

Create a dataset and ingest content as chunks:

// src/search/ingest.ts — Ingest documents into Trieve
const TRIEVE_API_URL = "https://api.trieve.ai";
const TRIEVE_API_KEY = process.env.TRIEVE_API_KEY!;
const DATASET_ID = process.env.TRIEVE_DATASET_ID!;

async function trieveFetch(path: string, options?: RequestInit) {
  const res = await fetch(`${TRIEVE_API_URL}${path}`, {
    ...options,
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${TRIEVE_API_KEY}`,
      "TR-Dataset": DATASET_ID,
      ...options?.headers,
    },
  });
  if (!res.ok) throw new Error(`Trieve error: ${await res.text()}`);
  return res.json();
}

// Create a chunk (the fundamental unit of searchable content)
async function ingestChunk(params: {
  content: string;
  link?: string;
  tag_set?: string[];
  metadata?: Record<string, any>;
  group_tracking_id?: string;     // Group related chunks (e.g., same document)
}) {
  return trieveFetch("/api/chunk", {
    method: "POST",
    body: JSON.stringify({
      chunk_html: params.content,           // HTML or plain text content
      link: params.link,                     // Source URL
      tag_set: params.tag_set,              // Tags for filtering
      metadata: params.metadata,
      group_tracking_ids: params.group_tracking_id
        ? [params.group_tracking_id]
        : undefined,
      upsert_by_tracking_id: true,          // Update if exists, insert if not
    }),
  });
}

// Bulk ingest for large datasets
async function bulkIngest(documents: any[]) {
  const chunks = documents.flatMap((doc) => {
    // Split long documents into smaller chunks
    const paragraphs = doc.content.split("\n\n").filter(Boolean);
    return paragraphs.map((paragraph: string, index: number) => ({
      chunk_html: paragraph,
      tracking_id: `${doc.id}-chunk-${index}`,
      link: doc.url,
      tag_set: doc.tags,
      metadata: {
        title: doc.title,
        author: doc.author,
        section_index: index,
      },
      group_tracking_ids: [doc.id],    // All chunks from same doc in one group
    }));
  });

  // Send in batches of 120 (API limit)
  for (let i = 0; i < chunks.length; i += 120) {
    const batch = chunks.slice(i, i + 120);
    await trieveFetch("/api/chunks", {
      method: "POST",
      body: JSON.stringify(batch),
    });
    console.log(`Ingested ${Math.min(i + 120, chunks.length)}/${chunks.length} chunks`);
  }
}

Search

Perform full-text, semantic, or hybrid search:

// src/search/query.ts — Search with different strategies
// Hybrid search — combines keyword matching with semantic similarity
async function hybridSearch(query: string, options?: {
  filters?: Record<string, any>;
  page?: number;
  pageSize?: number;
  scoreThreshold?: number;
}) {
  return trieveFetch("/api/chunk/search", {
    method: "POST",
    body: JSON.stringify({
      query,
      search_type: "hybrid",              // "fulltext" | "semantic" | "hybrid"
      page: options?.page ?? 1,
      page_size: options?.pageSize ?? 10,
      score_threshold: options?.scoreThreshold ?? 0.3,
      get_total_pages: true,
      highlight_results: true,             // Return highlighted snippets
      highlight_max_length: 200,
      highlight_max_num: 3,
      use_weights: true,                   // Balance keyword vs semantic scores
      filters: options?.filters ? {
        must: Object.entries(options.filters).map(([field, value]) => ({
          field: `metadata.${field}`,
          match_any: Array.isArray(value) ? value : [value],
        })),
      } : undefined,
    }),
  });
}

// Autocomplete / typeahead search
async function autocomplete(query: string) {
  return trieveFetch("/api/chunk/autocomplete", {
    method: "POST",
    body: JSON.stringify({
      query,
      search_type: "fulltext",            // Keyword-based for speed
      page_size: 5,
      highlight_results: true,
      highlight_max_length: 100,
    }),
  });
}

// Group search — return results grouped by document
async function groupSearch(query: string) {
  return trieveFetch("/api/chunk_group/group_oriented_search", {
    method: "POST",
    body: JSON.stringify({
      query,
      search_type: "hybrid",
      page: 1,
      page_size: 10,
      group_size: 3,                      // Show top 3 chunks per group
    }),
  });
}

RAG (Retrieval-Augmented Generation)

Use Trieve's built-in RAG to generate answers from your data:

// src/search/rag.ts — Generate answers using retrieved context
async function ragQuery(question: string) {
  const response = await trieveFetch("/api/chunk/generate", {
    method: "POST",
    body: JSON.stringify({
      prev_messages: [
        { role: "user", content: question },
      ],
      // Search configuration for retrieval step
      chunk_filter: null,
      search_type: "hybrid",
      page_size: 5,                       // Retrieve top 5 chunks as context
      // LLM configuration for generation step
      llm_options: {
        completion_first: false,          // Search first, then generate
        system_prompt: "Answer the user's question based on the provided context. If the context doesn't contain the answer, say so. Cite sources.",
        temperature: 0.3,                 // Low temperature for factual answers
        max_tokens: 500,
      },
      highlight_results: true,
    }),
  });

  // Response includes both the generated answer and the source chunks
  return {
    answer: response.message,
    sources: response.chunks.map((c: any) => ({
      content: c.chunk.chunk_html,
      link: c.chunk.link,
      score: c.score,
    })),
  };
}

// Streaming RAG for real-time response display
async function streamRagQuery(question: string, onChunk: (text: string) => void) {
  const response = await fetch(`${TRIEVE_API_URL}/api/chunk/generate`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${TRIEVE_API_KEY}`,
      "TR-Dataset": DATASET_ID,
    },
    body: JSON.stringify({
      prev_messages: [{ role: "user", content: question }],
      search_type: "hybrid",
      page_size: 5,
      stream_response: true,
    }),
  });

  const reader = response.body!.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const text = decoder.decode(value);
    onChunk(text);
  }
}

Recommendations

Get content recommendations based on chunk similarity:

// src/search/recommend.ts — Content recommendations
async function getRecommendations(chunkId: string, limit = 5) {
  return trieveFetch("/api/chunk/recommend", {
    method: "POST",
    body: JSON.stringify({
      positive_chunk_ids: [chunkId],     // "More like this"
      negative_chunk_ids: [],             // "Less like this"
      limit,
      strategy: "average_vector",        // Average vectors of positive examples
    }),
  });
}

// Recommend based on user reading history
async function personalizedRecommendations(readChunkIds: string[], limit = 10) {
  return trieveFetch("/api/chunk/recommend", {
    method: "POST",
    body: JSON.stringify({
      positive_chunk_ids: readChunkIds.slice(-5),  // Last 5 read articles
      negative_chunk_ids: [],
      limit,
      strategy: "average_vector",
      filters: {
        must_not: readChunkIds.map((id) => ({     // Exclude already-read content
          field: "id",
          match_any: [id],
        })),
      },
    }),
  });
}

Analytics

Track search performance and user behavior:

// src/search/analytics.ts — Search analytics and click tracking
// Log a search event
async function trackSearch(query: string, results: any[]) {
  await trieveFetch("/api/analytics/search", {
    method: "POST",
    body: JSON.stringify({
      query,
      search_type: "hybrid",
      results: results.map((r) => r.id),
    }),
  });
}

// Log when a user clicks a search result
async function trackClick(queryId: string, chunkId: string, position: number) {
  await trieveFetch("/api/analytics/search/click", {
    method: "POST",
    body: JSON.stringify({
      query_id: queryId,
      chunk_id: chunkId,
      position,                           // 1-indexed click position
    }),
  });
}

// Get search analytics — top queries, no-result queries, CTR
async function getAnalytics(params: { from: string; to: string }) {
  const topQueries = await trieveFetch(
    `/api/analytics/search/top_queries?from=${params.from}&to=${params.to}`
  );

  const noResults = await trieveFetch(
    `/api/analytics/search/no_result_queries?from=${params.from}&to=${params.to}`
  );

  return { topQueries, noResults };
}

Installation

# JavaScript/TypeScript SDK
npm install trieve-ts-sdk

# Or use the REST API directly (no SDK needed)
# All examples above use fetch — zero dependencies

Examples

Example 1: Integrating Trieve into an existing application

User request:

Add Trieve to my Next.js app for the AI chat feature. I want streaming responses.

The agent installs the SDK, creates an API route that initializes the Trieve client, configures streaming, selects an appropriate model, and wires up the frontend to consume the stream. It handles error cases and sets up proper environment variable management for the API key.

Example 2: Optimizing search performance

User request:

My Trieve calls are slow and expensive. Help me optimize the setup.

The agent reviews the current implementation, identifies issues (wrong model selection, missing caching, inefficient prompting, no batching), and applies optimizations specific to Trieve's capabilities — adjusting model parameters, adding response caching, and implementing retry logic with exponential backoff.

Guidelines

  1. Chunk intelligently — Split by paragraphs or sections, not arbitrary character counts; each chunk should be self-contained
  2. Use groups for documents — Group chunks from the same document so you can search by document or by chunk
  3. Hybrid search by default — Combines keyword precision with semantic understanding; switch to fulltext only for autocomplete
  4. Track analytics from day one — No-result queries tell you what content is missing; low-CTR queries reveal relevance issues
  5. Set score thresholds — Filter out low-confidence results; 0.3 is a good starting point, tune based on your data
  6. Use tags for filtering — Tags enable fast categorical filters without scanning metadata
  7. Upsert with tracking IDs — Use upsert_by_tracking_id to safely re-ingest content without creating duplicates
  8. Stream RAG responses — For user-facing applications, stream the LLM response to reduce perceived latency

> related_skills --same-repo

> zustand

You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.

> zoho

Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.

> zod

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

> zipkin

Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.

┌ stats

installs/wk0
░░░░░░░░░░
github stars17
███░░░░░░░
first seenMar 17, 2026
└────────────

┌ repo

TerminalSkills/skills
by TerminalSkills
└────────────

┌ tags

└────────────