Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/thePrnvBot/dispel-web-stylist/llms.txt

Use this file to discover all available pages before exploring further.

This page describes the internal pipeline that runs every time you submit a prompt in Dispel — from the moment you press Enter to the moment the styled page updates in front of you. Understanding this pipeline helps you write more effective prompts, troubleshoot unexpected output, and know exactly what data leaves your browser.

The Request Pipeline

1

Side Panel Reads Tab Context

Before any prompt is sent, the side panel queries the currently active tab to build a IPageContext object. This consists of two parts:
  • Meta — the tab’s full URL and page title, sourced from the browser’s tab API.
  • Viewport — the current inner width, height, and scroll position (scrollX, scrollY), retrieved by messaging the content script running in the tab via a GET_PAGE_META message.
The URL is later stripped of its query string before being included in the system prompt, to avoid leaking sensitive parameters to the AI provider.
2

Content Script Extracts Visible HTML

When you submit a prompt, Dispel’s content script runs extractViewportHTML() on the live page. This function walks document.body, collects only the elements that are currently visible in the viewport, and returns a sanitized HTML string. The extraction:
  • Strips entire tag families<script>, <style>, <noscript>, <meta>, <link>, <iframe>, <canvas>, <svg>, <head>, <base>, <template>, <path>, <mask>, and <defs> are removed entirely.
  • Removes hidden elements — elements with display: none, visibility: hidden, opacity: 0, hidden, or aria-hidden="true" are pruned from the clone before serialization.
  • Strips most attributes — only the following 13 attributes are kept on any element: id, class, style, href, role, data-testid, data-qa, type, name, placeholder, src, alt, and title. All others are removed.
  • Collapses whitespace — text nodes have leading/trailing whitespace trimmed and internal runs collapsed to a single space.
The result is a compact, stable HTML snapshot that gives the AI enough structural context to generate accurate CSS selectors without exposing application logic or sensitive attribute values.
3

Prompt, HTML, and Context Sent to AI Provider

The background service worker assembles the full request and calls streamChat(). The AI provider receives:
  • A static system prompt (STATIC_GUIDELINES) covering selector strategy, scoping rules, modern CSS practices, and the shadow DOM constraint — this is sent verbatim on every request.
  • A dynamic system prompt built from the IPageContext (URL without query string, page title, viewport dimensions and scroll position), any elements picked with the element picker, and the accumulated CSS from previous turns in this draft session.
  • The user’s message as the first and only user turn.
  • The set of agent tools the model may call (see the next section).
4

Provider Streams CSS; Dispel Applies It Live

streamChat() uses the Vercel AI SDK’s streamText() to open a streaming connection to the provider. As tool-result chunks arrive, toStreamChunk() maps them to typed StreamChatChunk objects:
  • A chunk from the generateCss tool becomes { type: "css", css: "..." }.
  • A chunk from the reportError tool becomes { type: "error", code: "...", message: "..." }.
The outer streamCSS() function accumulates CSS chunks into a growing string. After each new chunk, if the accumulated CSS has changed, it calls applyCssToTab(), which sends an APPLY_CSS message to the content script in the target tab. The content script inserts or replaces a <style> element in the page’s <head>, so styles appear — and update — in real time as the model is still writing.
5

Draft Turn Appended to Storage

Once the stream completes (or errors), the final CSS string is returned to the service that initiated the request. The caller appends the completed turn — including the prompt text and the generated CSS — to the active draft in local extension storage. This draft accumulates across turns for the current session until you either save it (moving it to the permanent per-site prompt store) or discard it.

The AI Agent

Dispel does not send a bare chat request to the provider. It uses a tool-calling agent loop powered by streamText() from the Vercel AI SDK, with up to four steps per request. The model is given three tools and must use one of the terminal tools to produce output — it may never respond with plain text.
Description (from source): “Generate CSS styles to the page. Return only valid CSS rules with no markdown, explanations, or comments.”The model calls this tool with a single css string argument containing raw CSS rules targeting specific selectors on the page. The tool’s execute function simply returns the CSS string as-is, which becomes the tool-result chunk that streamChat() maps to a { type: "css" } chunk and streams to the page.
Description (from source): “Report why the CSS request cannot be fulfilled with a specific error code and message.”When the model determines that the request cannot be fulfilled — for example, when the target element is inside a Shadow DOM, or the prompt is ambiguous — it calls reportError with a typed code from the LLM_ERROR_CODES enum and a human-readable message. This becomes an { type: "error" } chunk that the UI surfaces to the user.
Description (from source): “Fetch cleaned HTML of the current viewport. Call with no selector to see all visible top-level elements. Call with a selector to inspect a specific element. Returns the HTML string, or ‘Element not found in current viewport’ if the selector does not match a visible element.”This tool lets the model request a fresh snapshot of the page’s visible HTML mid-run when it needs more DOM context to generate accurate selectors. It accepts an optional CSS selector to scope extraction to a single element. Importantly, getPageHTML may only be called once per request — the prepareStep hook in streamText() removes it from the available tool list after the first time it has been used in any step, forcing the model to proceed to generateCss or reportError with the information it has gathered.
The agent loop is bounded by stopWhen conditions passed to streamText(): the stream terminates immediately after the model calls either generateCss or reportError, or after four steps have elapsed — whichever comes first. This prevents unbounded tool-call loops and keeps latency predictable.

CSS Scoping Guidelines

Every request includes STATIC_GUIDELINES, a fixed system-prompt section that instructs the model on how to write safe, precise, and maintainable CSS. The key rules are: Selector strategy — prefer stable, minimal selectors in this order:
  1. id selectors (#id)
  2. data-testid, data-test, data-qa attributes
  3. Class selectors (.class)
  4. Structural selectors (tag, :nth-child, descendant combinators)
The extracted HTML snapshot provides these stable selectors; the model is instructed to use them rather than inventing new ones. Scoping and safety — strictly limit the blast radius:
  • Scope every rule to the smallest relevant element or container.
  • Never affect unrelated parts of the page.
  • Never modify global layout unless the prompt explicitly requests it.
  • Forbidden patterns: universal selectors (*) except when strictly required; all: unset or all: initial; styling html or body without an explicit request; excessive use of !important; position: fixed or position: absolute on major layout elements without justification.
Modern CSS — write clean, responsive output:
  • Use flexbox, grid, gap, clamp(), and other modern layout and sizing primitives.
  • Prefer responsive units (%, rem, vw, vh) over fixed px where appropriate.
  • Use shorthand properties where they improve readability.
  • Use CSS variables only if they genuinely improve clarity and reuse.
External resources — avoid remote dependencies:
  • Do not include remote fonts, @import URLs, CDN-hosted assets, or external images unless the prompt explicitly asks for them.
  • Prefer pure CSS solutions and system fonts.
Dispel’s CSS is injected into the main document’s <head>. It cannot reach elements that live inside a Shadow DOM — the browser’s style encapsulation boundary prevents injected stylesheets from crossing into shadow roots. If you target an element inside a Shadow DOM, the model is instructed to call reportError rather than generate CSS that would silently have no effect.

Data Flow: Local vs. Provider

Understanding what stays on your device and what is transmitted helps you use Dispel with confidence. Stays entirely local (browser extension storage):
  • Your API keys for all configured providers.
  • All saved prompts and their generated CSS.
  • Active draft turns for the current session.
  • Extension settings (theme preference, selected model, etc.).
Sent to your configured AI provider on each request:
  • The static STATIC_GUIDELINES system prompt (fixed text, no personal data).
  • The dynamic system prompt section containing the stripped page URL (no query string), page title, viewport dimensions, any element picker HTML, and the accumulated CSS from this draft session.
  • Your prompt message text.
  • Tool call results (cleaned viewport HTML returned by getPageHTML, if the model invokes it).
No data is sent to any Dispel-operated server. The only outbound network traffic is the direct HTTPS connection from your browser to the AI provider API endpoint you configured.

Build docs developers (and LLMs) love