Get started
Core concepts
A handful of ideas you'll see on every page. If you only read one documentation page, make it this one.
Workspace
Every piece of data in Blengi belongs to exactly one workspace. Users can be members of multiple workspaces and switch between them; agents, conversations, leads, sources, and analytics never cross the boundary.
Multi-tenancy is enforced by the BelongsToWorkspace Eloquent
trait, which adds a global scope filtering every query by the current
workspace. There's a regression test (MultiTenancyTest) that
fails the build if a tenant-scoped model is queried without it.
Agent
An agent is the unit you embed. It owns a persona, system prompt, theme, starter prompts, allowed origins, behavior rules, and — importantly — its own knowledge sources. One workspace can have many agents (e.g. one for your marketing site, one for your help center).
Agents have a draft and a published state.
A draft does not start on any website: /widget/init answers
404 for it, except for the preview inside the dashboard.
Once published, the widget reads the agent's current settings, so every
save is live for visitors straight away — there is no separate
published copy. Each publish also stores a copy of the settings as an
agent_version row, which Advanced › Earlier
versions can restore.
Knowledge source
A source is anything you want the agent to learn from: a URL, a sitemap, a feed, pasted text, a Notion page, a Google Doc, or — when the auto-index toggle is on — pages visitors land on. Each source produces one or more documents; documents get chunked into ~500-token pieces, embedded, and upserted into the vector store.
See Knowledge sources for the ingestion flow and RAG pipeline for how retrieval works.
Conversation
A conversation is a thread between one visitor and one agent. It survives
page reloads — when the widget re-inits within 24 hours, we resume the
most recent conversation instead of starting a new one. Messages have
roles: user and assistant, plus
internal-note for your team's notes. A team member's reply
after taking a chat over (on the conversation screen) is stored as an
assistant message with model
human:<user id>; the widget receives it as
human-agent.
The row is written the moment the widget loads
(/api/v1/widget/init), whether or not the visitor ever
types, so the raw table counts widget sessions, not
chats. Everywhere the product says "conversations" — the dashboard
tiles, the Conversations overview (which opens on "Engaged only") and
the agents list — it means sessions where the visitor sent at least
one message; Conversation::engaged() is the one shared
definition. The dashboard prints the session count under the
Conversations tile so both numbers stay visible: a site with 6,000
widget loads and 7 real conversations a week reads exactly like that.
Lead
A lead is a visitor whose contact info you've captured (name, email, phone, plus any custom fields you defined). The widget asks for these inline when the conversation reaches a threshold of intent — see Voice, leads & persistence. Leads dedupe on email per agent so the same person filling out the form twice doesn't create two rows.
Plan
Plans are platform-admin-managed subscription tiers (Free, Pro, etc.).
Each plan defines a monthly conversation quota and a
features blob — currently features.remove_branding
is the only flag, but it's an open shape. Plans automatically sync to
Stripe as Products + Prices, so admins never touch the Stripe dashboard.
Hot path
"Hot path" means the visitor-message → first-token path. It has a hard 1-second p95 latency target — no DB writes, no synchronous webhooks, no retries. The pipeline streams tokens out, then dispatches persistence and analytics work asynchronously after the stream completes. See Hot path & latency.
Origin allow-list
The widget script is public — anyone who finds your data-agent-id
can paste it on their own site. The /v1/widget/init endpoint
enforces a strict origin allow-list per agent: empty list denies
everywhere, otherwise exact scheme://host matching with no
subdomain inference. Allowed origins
has the rules.
Super admin vs. workspace member
A workspace member sees the customer surface (/dashboard,
/app/agents, /app/leads, /settings/billing). A super-admin
additionally sees the platform console at /admin for managing
plans, watching usage, retrying failed jobs, and impersonating customers
for support. The flag is users.role = SuperAdmin and is gated
by the EnsureSuperAdmin middleware (which returns 404, not 403,
so the panel doesn't reveal its existence).