bento-chat
v0.1.0
Published
Drop an AI-quality chatbot onto any website with zero LLM API cost. Bake your knowledge locally with a coding agent, ship one bundle.json, answer in-browser with no API.
Downloads
29
Maintainers
Readme
🍱 bento-chat
Drop an AI-quality chatbot onto any website — with zero LLM API cost.
Bake your knowledge locally with a coding agent (Claude Code, Codex, Gemini).
Ship a single bundle.json. The browser answers questions with no API, no
server, no per-message billing — just fast, predictable, on-device retrieval.
Why
Running an LLM on your website means metered, per-message billing that scales with traffic. bento-chat flips it: you already pay a flat subscription for a local coding agent, so do the expensive “make it smart” work once, offline, and serve the result for free forever.
| | LLM-on-website | bento-chat | |---|---|---| | Cost per message | 💸 metered | 0 | | Latency | network round-trip | instant (in-browser) | | Privacy | data leaves the page | 100% on-device | | Answers | can hallucinate | predictable, curated | | Infra | API keys + backend | one static JSON file |
How it works
┌─ LOCAL (once, with your agent subscription) ──────────────┐
│ raw notes / FAQ / docs │
│ │ Claude Code / Codex / Gemini reads AGENT.md │
│ ▼ → rewrites, adds synonyms & paraphrases │
│ enriched data/ ──► bento-chat build ──► bundle.json │
└───────────────────────────────────────────────────────────┘
│ (commit / upload the one file)
┌─ WEBSITE (every visitor, free & instant) ─────────────────┐
│ <bento-chat src="bundle.json"> → in-browser engine │
│ normalize → BM25 keyword match → curated answer │
└───────────────────────────────────────────────────────────┘The trick: the agent does all the “semantic” work offline — generating the synonyms, paraphrases, and missing questions a real user might type — so a plain keyword engine in the browser feels like an LLM, at zero runtime cost.
Quick start
# 1. scaffold a project (sample data + AGENT.md + config)
npx bento-chat init my-bot && cd my-bot
# 2. bake your data with your agent
# open AGENT.md in Claude Code / Codex / Gemini and let it enrich ./data
# (or run `bento-chat agent-prompt` to print the instructions)
# 3. compile the runtime bundle
npx bento-chat build ./data -o ./bundle.json
# 4. smoke-test from the terminal
npx bento-chat ask ./bundle.json "how much is shipping?"Embed on any page with one script tag and one element — no bundler, no build step:
<!-- English UI -->
<script src="https://unpkg.com/bento-chat/dist/bento-chat.min.js"></script>
<bento-chat src="/bundle.json" lang="en" accent="#4f46e5"></bento-chat><!-- Japanese UI -->
<script src="https://unpkg.com/bento-chat/dist/bento-chat.min.js"></script>
<bento-chat src="/bundle.ja.json" lang="ja" accent="#e11d48"></bento-chat>Pick the UI language at embed time with lang="en" or lang="ja" — it switches
the placeholder, send button, greeting, and "not found" message. Point src at
the bundle you baked for that language. Every label is also overridable
(title, subtitle, placeholder, greeting, fallback).
Or call the engine directly:
import { Chatbot } from "bento-chat";
const bot = Chatbot.fromJSON(await fetch("/bundle.json").then(r => r.json()));
console.log(bot.ask("How much is shipping?").answer);Data format
[
{
"id": "shipping-fee",
"category": "support",
"question": "How much is shipping?",
"answer": "Shipping is a flat $5 nationwide. Orders over $50 ship free.",
"keywords": ["shipping", "delivery", "postage", "cost", "free", "fee"]
},
{
"id": "pro-plan",
"entity": "Pro plan",
"facts": { "price": "$19/month", "members": "up to 10" },
"keywords": ["pricing", "plan", "upgrade"]
}
]JSON, JSONL, and CSV (question,answer,category) are supported. keywords is
where the magic lives — that’s what the agent enriches, and what makes keyword
retrieval feel semantic.
CLI
| Command | What it does |
|---|---|
| bento-chat init [dir] | Scaffold data/, bento.config.json, and AGENT.md. |
| bento-chat build <dir> -o bundle.json | Compile sources into a runtime bundle. |
| bento-chat ask <bundle> "q" | Query a bundle from the terminal. |
| bento-chat agent-prompt | Print the agent baking instructions. |
API
new Chatbot(bundle)/Chatbot.fromJSON(json)— construct the engine.bot.ask(query, opts?)— synchronous, zero-API. Returns{ answer, matched, score, entry, alternatives, method }.bot.askHybrid(query, opts?)— optional embedding-blended search (needs a bundle with embeddings + a query embedder).
score is query-term coverage (0..1); answers below opts.threshold
(default 0.34) return the bundle’s fallback.
Multilingual (English / Japanese)
Two independent language layers:
- UI language — set at embed time with
lang="en"orlang="ja". Switches the widget's built-in labels and messages. - Content language — the bundle itself. Bake one bundle per language
locally (e.g.
bundle.en.json,bundle.ja.json) and pointsrcat the one you want.
The retrieval engine is language-agnostic: Latin words are stopword-filtered,
and CJK (Japanese/Chinese) text is indexed as character bigrams — so Japanese
FAQ works out of the box with no morphological analyzer and zero dependencies.
See examples/japanese for a full JA demo.
Run this repo
npm install
npm run demo # builds the package + example bundle, prints how to serve
npx serve . # then open /examples/basic/index.html
npm run smoke # end-to-end retrieval testRoadmap
- ✅ BM25 keyword engine, multilingual tokenizer, web component, CLI
- ⏳ Optional in-browser embeddings (transformers.js) for true hybrid search
- ⏳ YAML sources, multi-bundle routing, click-feedback (analytics-free)
- ⏳
bento-chat optimize— agent-in-the-loop keyword tuning from failed queries
License
MIT © tinaba96
