Skip to main content

Motivation

Most “chat widget” products are a stateless text box bolted to a generic LLM. KITT is the embeddable surface of the same AskMyDocs retrieval + agentic stack — so a public website gets grounded, cited answers backed by your canonical KB, plus optional agentic actions on the page.

What it does

  • Grounded Q&A with citations — every answer is backed by your KB, same retrieval pipeline as the main chat (see chat & retrieval).
  • Page-aware — KITT reads a snapshot of the host page so it can answer about what the visitor is looking at.
  • Agentic — when allowed, the LLM emits tool calls executed in the page DOM (click / type / select / navigate_to / submit_form / wait_for + more) or server-side via /exec-tool (e.g. search_knowledge_base), in a bounded loop with per-session step + consecutive-error caps.
  • Skills — JSON manifests under resources/widget/skills/* declare which tools are available, auto-annotation rules, and run policies.

Embedding it

The loader reads its config from the script tag (data-public-key, optional data-api-base) or from a window.AskMyDocsWidget global. The widget authenticates with that public key (minted in the admin under /app/admin/widget, super-admin gated) over a dedicated public channel (widget.key middleware), separate from the Sanctum admin stack. Use data-kitt-skip on any host-page DOM region to keep sensitive content out of the page snapshot (the data-kitt-* attributes annotate the host page for the agent; they are distinct from the loader’s data-public-key). KITT has three layout modes: helper (floating launcher), inline (fills a host mount element) and fullscreen (always-open viewport). Fullscreen is an embed-time mode, not an enter/exit toggle inside the chat:
The fullscreen panel is an accessible region, has no launcher/close control, and does not force focus during bootstrap. While identity and history load it exposes data-state="loading" and aria-busy="true" and keeps the composer disabled.

Page-native welcome content

Before the first message, KITT can render a branded empty-state card explaining what the chat is for. Configure a reusable default on the widget key, then let the host backend override it per page through window.AskMyDocsWidget.intro:
The runtime precedence is key default → host override; intro: false disables a saved card on a specific page. Existing authenticated history suppresses the card. Suggestion chips send their prompt as the first user message. All fields are bounded plain text, images must use HTTPS and arbitrary HTML is never accepted, so tenant-controlled content cannot escape the Shadow DOM renderer. The admin’s Appearance → Welcome tab provides the same contract with a live preview. Operators can also inspect or update it with widget:intro, while the read-only WidgetIntroConfigTool exposes the resolved configuration to MCP clients without returning widget credentials.

Authenticated users and history

Enable Authenticated users on a widget key to receive a one-time, server-only ik_ credential. The host backend—not browser JavaScript—exchanges an immutable internal subject for a short-lived, origin-bound wu_: The subject should be an immutable UUID or a host-side HMAC, not an email. AskMyDocs stores only a keyed hash. userTokenUrl must be same-origin with the host page, session-protected, and return exactly:
GET /api/widget/sessions/current is separate from paginated history. It filters active, waiting_user, and waiting_tool, orders by updated_at DESC, id DESC, and returns one row or 204. Tenant, widget key, project and pseudonymous identity are enforced on the server, so a different user or key cannot restore the conversation.

Credential and token lifecycle

Every mutation carries the current identity_credential_version. A stale admin tab receives 409 identity_credential_conflict instead of overwriting a newer credential. Mutations are tenant-scoped, row-locked, transactional and audited without plaintext or hashes. There is no MCP mutation for ik_. This is a deliberate R44 exception: a one-time server credential must not appear in an agent transcript. PHP (WidgetIdentityCredentialService and widget:identity-credential) and the RBAC-gated admin HTTP surface share the same core.

Operator examples

Admin HTTP adapters:
  • PATCH /api/admin/widget-keys/{id} with { "user_auth_enabled": false, "identity_credential_version": 3 };
  • POST /api/admin/widget-keys/{id}/rotate-identity-secret with { "identity_credential_version": 3 }.
The plaintext is returned only when enable creates it or rotate replaces it. Store it in the host secret manager before closing the response.

Security model

KITT enforces tenant isolation, an exact-match origin allowlist, no-credential CORS, credential-field and navigation guards, and a per-session rate limit. The inherent risks of a public embeddable agent (public-key abuse, prompt-injection, data egress to the LLM) and the operator mitigations are documented in the integration guide’s threat-model section. For authenticated embeds, add these controls:
  • never put ik_, the raw subject or a static long-lived wu_ in HTML;
  • require the host’s normal authenticated session on userTokenUrl;
  • send Cache-Control: no-store and keep wu_ memory-only;
  • keep the configured origin exact, including scheme and non-default port;
  • on logout, stop serving the host-token endpoint and reload/remove the widget;
  • use disable—not rotation—when immediate user-token revocation is required.

Gotchas & operations

  • The widget key is public — treat it like a publishable key; rotate via the admin (super-admin only).
  • ik_ is not public — it belongs in the host backend’s secret manager.
  • A host-token failure is a hard authenticated-mode error: KITT does not fall back to a guest conversation.
  • data-kitt-skip is the operator’s lever to keep sensitive regions out of the snapshot — use it on auth’d/account areas.
  • Agentic actions are bounded (step + consecutive-error caps + a snapshot byte cap) — these are safety limits, not tuning knobs to crank.

Chat & retrieval

The grounded retrieval KITT shares with the main chat.

Multi-tenant isolation

How KITT sessions stay scoped to one tenant.