Documentation · v0.3

Getting started

Sir Chats-a-Lot is an open-source React widget that drops an LLM-driven chat panel onto your site. It answers visitor questions from your published content via Gnosys Web, and renders forms / buttons / confirms inline when a text reply isn't enough.

This doc walks you through the five-minute install, the configuration surface, the API contract between the widget and your server, and the basics of theming and self-hosting.

Note
The widget is browser-only. API keys, rate limiting, and content moderation live in YOUR server route — never in the package. That's an intentional liability boundary.
01 · Quick start

Install

Add the package:

npm install sir-chats-a-lot

Mount it in your React app (Next.js App Router shown; the same component pattern works anywhere you can render React):

app/scal.tsx
"use client";

import {
  SirChatsALotProvider,
  SirChatsALotLauncher,
  SirChatsALotWidget,
} from "sir-chats-a-lot";
import type { AgentRequest, SirChatsALotApi } from "sir-chats-a-lot";
import "sir-chats-a-lot/styles";

const api: SirChatsALotApi = async (request: AgentRequest) => {
  const res = await fetch("/api/scal", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(request),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
};

export function AppScal() {
  return (
    <SirChatsALotProvider productName="My SaaS" api={api}>
      <SirChatsALotLauncher />
      <SirChatsALotWidget />
    </SirChatsALotProvider>
  );
}

You'll also need a server route at /api/scal that talks to your LLM provider. The repo ships examples/nextjs-anthropic and examples/nextjs-openai as reference implementations.

02 · Configure

Configuration

The provider accepts these props (all optional except productName and api):

PropTypeDefaultPurpose
productNamestringShown in the launcher and header
api(req) => Promise&lt;res&gt;Your server-route caller
rateLimitMsnumber2000Cooldown between sends/submits
maxMessageLengthnumber2000Character cap per message
maxMessagesnumber50Conversation history cap
greetingstringFirst assistant message when chat opens
subtitlestring"AI assistant"Header subtitle
themeobjectColor/radius/font overrides
userobjectOptional visitor context sent to your route
onErrorfnObservability hook
onMessagefnPer-message hook
onClosefnRuns when the panel closes
persist"none" | "session" | "local""none"Conversation storage mode
persistKeystringRequired when persist is not "none"
clearOnClosebooleanfalseClears the thread when the panel closes
idleTimeoutMsnumberAuto-closes after inactivity
modesModeRegistryNamed flows opened by intent
launcherobjectLauncher position, label, and aria label
03 · Grounding

Knowledge layer

SCAL pairs with gnosys/web — a zero-dependency static knowledge index. The CLI crawls your site (sitemap, directory, or URL list), produces markdown, and builds a TF-IDF index with optional build-time embedding vectors for hybrid semantic search. Your server route loads the index and feeds matches to the LLM each turn.

Setup

Install Gnosys, initialize a web config, and build the index:

npm install gnosys
npx gnosys web init
npx gnosys web build

Then add "postbuild": "gnosys web build" to your package.json scripts so the index regenerates on every deploy.

Semantic search (optional)

Add embedding vectors at build time when you want hybrid semantic ranking. The route embeds only the user's query; if vectors are missing, the provider key is unavailable, the embed request fails, or the vector model does not match, search falls back to the lexical index.

npx gnosys web build --embeddings openai

Use the same embedding model at build and query time. The generated route handles the check; the OpenAI example uses text-embedding-3-small, and the Anthropic example uses Voyage when configured.

Note
You don't have to use Gnosys. The widget contract is provider-agnostic; bring your own RAG, vector DB, or whatever your stack already has.
04 · Dynamic UI

Surfaces API

Every turn, your server returns an AgentResponse. It can include text, a surface, or both. The LLM picks which surface (if any) to send based on what the visitor needs next.

Built-in surface types

TypePurpose
quickActionsRow of tappable suggestion cards
formLabeled fields with validation and a submit button
confirmYes/no dialog
composedMixed text/field/button/divider blocks

Response shape

AgentResponse
{
  "message": "Two paths to install — pick one:",
  "surface": {
    "type": "quickActions",
    "props": {
      "actions": [
        { "id": "npm",    "label": "NPM package" },
        { "id": "cli",    "label": "scal init" },
        { "id": "manual", "label": "Manual route" }
      ]
    }
  },
  "sources": [
    { "title": "Installation guide", "path": "/docs/install" }
  ]
}

When the visitor interacts with a surface, the widget sends an AgentAction back with the payload. Your server feeds that to the LLM and the next turn decides what to do next — reply, send a follow-up surface, or finish.

05 · Look & feel

Theming

Every visual aspect is driven by CSS custom properties (--scal-color-accent, --scal-radius-panel, etc.). Override via the theme prop or define CSS variables on the host page. Host theme detection also recognizes common aliases such as --scl-accent.

import { SirChatsALotProvider } from "sir-chats-a-lot";

<SirChatsALotProvider
  productName="My SaaS"
  api={api}
  theme={{
    colors: {
      accent: "#d49b3a",
      background: "#0a100e",
      elevated: "#17211f",
      foreground: "#e3ddca",
      muted: "#a8a091",
      border: "#2b3431",
      accentForeground: "#0a100e",
    },
    radius: {
      panel: "14px",
      button: "999px",
      input: "10px",
    },
    typography: {
      fontFamily: "Inter, system-ui, sans-serif",
    },
  }}
>
  ...
</SirChatsALotProvider>
06 · Ownership

Self-hosting

SCAL is browser-only. Your server route owns the API key, rate limiting (server-side, in addition to the widget's client-side cooldown), prompt-injection defense, and content moderation. The package never makes outbound LLM calls itself.

Note
Need less route boilerplate? Pro adds a drop-in server handler, provider adapters, skill files, debug mode, and compliance hooks under a commercial license. The OSS widget does not require it.

The minimum your route needs to do:

  • Accept a POST with the AgentRequest JSON body
  • Retrieve relevant content from your knowledge index (Gnosys Web or other)
  • Call your LLM with the system prompt + retrieved context + conversation history
  • Validate the LLM's JSON response, returning an AgentResponse
  • Return { blocked: true } for moderation failures, or { error: "..." } for system failures
07 · FAQ

FAQ