← Back to work

Xelsus product · Website AI assistant

Skipping RAG on purpose: a grounded website assistant built in three days, then packaged to deploy again

Alfred answers visitors in English or Spanish using only the site’s own content. The interesting part is everything around the model: cached context instead of retrieval infrastructure, attacks blocked before they cost a token, tests that never call the model, and an agent skill that installs the whole thing on another site.

Try Alfred live ↗
Product
Xelsus.ai, live on a consultant’s website
Scope
AI assistant, analytics, reusable agent skill
Timeline
About three days, 2026
Role
Product and engineering

~3 days

From first commit to a live bilingual assistant and a reusable agent skill

0 tokens

Spent on blocked prompt-injection attempts. A pre-filter answers before the model is called

32

End-to-end browser tests, run against a simulated stream so they never call the model

1 command

To install the assistant on another Next.js site, through an AI coding agent skill

01

The problem

A consultant’s website was a static portfolio. Visitors could not ask “do you do this?” and get an answer grounded in the real services, case studies and articles, in their own language.

The constraints were the ones every small business has: running cost close to zero, no invented claims about the business, no leaking of the assistant’s instructions, and a public endpoint that would attract abuse from day one.

02

Why it was hard

  • A public endpoint invites prompt injection, attempts to extract the instructions, and plain spam.
  • The assistant must never invent services, prices or claims about the business it represents.
  • Running cost had to stay close to zero for a personal site.
  • Streaming chat interfaces are hard to test, and tests that call a real model are slow, flaky and billed.
  • On serverless hosting, work scheduled after a streamed response can be silently dropped.

03

What we built

A chat widget that follows the visitor across pages, a streaming API with layered guardrails, the site’s content summarized and cached at the model provider, and conversation analytics. Then the whole build was turned into an agent skill that asks a few setup questions and installs the assistant on another site.

Visitor: chat widget, conversation kept across pages
Rate limit → injection pre-filter: suspicious input is answered without calling the model
Site content summarized per language, cached at the model provider
Fallback: the same instructions sent inline if the cache is unavailable
Streaming answer, only from approved pages, with links in the visitor’s language
Conversation analytics in a Postgres database
Agent skill: installs the assistant on another site

04

Where the innovation is

01

Skipping RAG, on purpose

Once summarized, the whole site fits in the model’s context. So instead of a vector store and a retrieval pipeline to maintain, the content is uploaded once per language to the provider’s context cache and refreshed before it expires. Cached context is billed at a fraction of normal input tokens, and there is nothing extra to keep in sync.

02

Attacks that cost zero tokens

Messages that match known injection patterns never reach the model. The server answers them itself, in the same streaming format as a real reply, so the visitor sees a polite, in-character response and no tokens are spent. It is one layer among several: hardened instructions, a narrow scope, a short history window, an output cap and rate limiting.

03

Grounded links, in the visitor’s language

The assistant may only link to an approved list of pages, must match the link language to the conversation and may not invent anchors. On vague questions it asks for clarification instead of guessing, and it never quotes prices.

04

It degrades gracefully

If the context cache cannot be created, the same instructions go inline and the visitor notices nothing. When the hosting runtime turned out to drop work scheduled after the stream ended, conversation logging moved to the browser, after the answer is complete.

05

Tests that never call the model

A test fixture reproduces the exact streaming format of the AI SDK, so 32 end-to-end browser tests cover the widget’s real behavior without a model call, an API key or a bill.

06

One build, a repeatable delivery

The whole implementation is packaged as an AI coding agent skill. It asks a handful of setup questions, detects how the target site is built, scaffolds the files, creates the analytics tables with row-level security when the database tooling is connected, updates the security policy and verifies the endpoint before finishing.

05

Where the engineering went

A website assistant is easy to demo and hard to run in public. Most of the work went into the parts visitors never see: what happens to a message before the model, and what happens when something fails.

What happens to a message

The checks every message passes before it can reach the model.

Request path

Four checks before the model

Rate limit
Per visitor address
Pre-filter
Known injection patterns
History
Last 10 messages
Answer
Capped length

If a check fails

  • The visitor gets a polite reply, in character
  • The model is never called
  • No tokens are spent

06

Results

  • Live on a consultant’s website, answering in English and Spanish from the site’s own services, case studies and articles.
  • Built in about three days, from the first commit to the packaged agent skill.
  • Prompt-injection attempts that match known patterns are answered without a model call, at zero token cost.
  • 32 end-to-end tests cover the widget against a simulated stream, with no model calls and no API bill.
  • Every conversation is logged for analytics, so the next step is measuring what visitors actually ask and adding a small evaluation set for out-of-scope questions and injection variants.
  • The same assistant can now be installed on another Next.js site through a guided agent skill.

07

What we learned along the way

Not every assistant needs retrieval

RAG is often the reflex. When the content fits in context, caching it is simpler, cheaper and has fewer moving parts. Retrieval becomes worth it when the content outgrows the context, not before.

On serverless, the work ends when the stream ends

Logging that ran after the streamed answer was quietly dropped by the hosting runtime. Moving it to the browser, once the answer is complete, fixed it without adding infrastructure.

A filter is a layer, not a wall

Pattern matching stops known attacks cheaply, but it will never catch everything. The real protection is the stack: a narrow scope, hardened instructions, short context, capped answers and rate limits.

Stack

  • Next.js
  • React
  • Vercel AI SDK
  • Gemini 3 Flash
  • Gemini context caching
  • Supabase (Postgres, row-level security)
  • GSAP
  • Playwright
  • Netlify
  • Claude Code skills
  • MCP

Want an assistant that only says what your site can back up?

We build and deploy grounded assistants for your website, with guardrails, analytics and tests from day one.

Book a discovery session

Alfred runs live on its author’s own website. Usage figures will be added once there is enough data to report them honestly.