Skip to main content
Build

Knowledge base

Northwind Vault

Northwind Vault is a demo document portal built around semantic search. It has no content model at all — it leans on the media library. You upload PDFs and text files, Headless embeds them, and a search for “what happens if my laptop gets stolen” surfaces the incident runbook by meaning, with the matching passage highlighted. Here’s how you’d build your own.

Semantic search over your files
headless.build/demos/demo-docs
The Northwind Vault demo — a large search box over an internal document library, with example queries and a list of files.

Step 0

The content model

Here’s the shape you’re aiming for. You don’t have to build it by hand — the next steps have an agent create it for you — but it helps to see the target first. Expand a type to see its fields.

mediaMedia7 fields

No content types — just uploaded files. Headless embeds each one so it’s searchable by meaning.

  • filenameText
  • titleText
  • urlTextsigned download link
  • mimeTypeTextapplication/pdf, text/plain, …
  • sizeNumber
  • _similarityNumberrelevance, on search hits
  • _matchedChunkJSONthe passage that matched

The recipe

Build your own with an agent

Use this as a blueprint, not a script — adapt the fields and copy to whatever you’re making. Each step is a real prompt you can hand to a coding agent like Claude Code with the Headless MCP server connected; the terminals show the tool calls the agent makes, and the code is what it produces.

  1. Create the project & turn on semantic search

    Semantic search is a per-project switch. Have the agent create the project and enable it — from then on, every file you upload gets embedded and indexed by meaning.

    MCP · Headless
    # Create the project and switch on semantic search
    claude "Create a project called Northwind Vault and enable semantic search on it"
    create_project { name: "Northwind Vault", slug: "demo-docs" }
    update_project { semanticSearchEnabled: true }
    → uploads will be embedded and searchable by meaning
  2. Upload your documents

    There are no content types to model here. Point the agent at your files and it uploads them straight to the media library, where Headless embeds each one in the background.

    Claude Code
    # No content types — just files
    claude "Upload our policies, runbooks, and reports — the PDFs and text files in ./docs"
    upload_media × 9 (filename, content, mimeType)
    → 9 documents uploaded, embedded, and indexed
  3. Mint a read-only API key

    The portal searches from the browser, so create a public, read-only key under Project Settings → API Keys. Test it by asking a question in plain language, not keywords.

    Terminal
    curl -s "https://headless.build/api/v1/demo-docs/media?semantic=stolen%20laptop&limit=3" \
      -H "X-API-Key: hls_live_your_read_only_key" | jq
  4. Build the search UI

    Now the frontend. Semantic search is just the media endpoint with a `semantic` query parameter — Headless returns each hit with a relevance score and the exact passage that matched, so the UI can show why a result came back.

    Claude Code
    # A search box over the media library
    claude "Write a single self-contained index.html: a search box that queries the media library semantically and renders each result with its matched passage and a relevance score"
    Write public/demos/demo-docs/index.html
    → 1 file · one endpoint · meaning-based search
    index.html
    // Semantic search is just the media endpoint with a `semantic` query.
    async function search(q) {
      const params = new URLSearchParams({
        semantic: q,          // a natural-language question, not keywords
        threshold: "0.12",    // minimum relevance to return
        limit: "10",
      });
      const res = await api(`/media?${params}`);
      if (res.semanticSearchEnabled === false) return showEnableNotice();
    
      // Each hit says how well it matched, and the passage that matched.
      return res.data.map((asset) => ({
        title: asset.title,
        score: asset._similarity,
        passage: asset._matchedChunk?.text,
      }));
    }
  5. Ship it

    Point it at any pile of documents and deploy. There’s no schema to maintain — the meaning of the text is the index. Drop in a new file and it becomes searchable within moments, no code change required.

Build your own in an afternoon.

Model your content once, point an agent at it, and ship. Every project speaks REST, GraphQL, and MCP from the first entry.