B Blengi docs

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).