Skip to content
KONIGI

AI Assistants / In-product assistance / AI entry point

1 of 5

AI entry point

The feature has to be findable inside a product people already know, without retraining them on it.

Updated September 12, 2026

Problem

A capable assistant is worth nothing if nobody opens it. It has to be discoverable inside an interface people already navigate by habit, without displacing a control they use daily and without a tour.

Solution

Put the affordance next to the object it acts on. An assist that rewrites a paragraph belongs at the text selection. One that summarises a document belongs in the document’s header. One that answers questions about a dataset belongs beside the dataset. Proximity does the explaining that an icon can’t, and it’s the difference between a control people understand on sight and one they have to be told about.

HAX guideline 7 calls this efficient invocation. The useful reading is that invocation cost includes the cost of finding the thing in the first place. A global button in a corner is cheap to build and expensive to use, because the viewer has to carry the object to the assistant instead of the assistant arriving at the object.

The sparkle deserves a paragraph of its own. It became the field’s universal marker in about two years, and its meaning has correspondingly collapsed: it now signals that something is AI rather than what that something does. A sparkle on its own is close to unlabelled. Pairing the icon with a verb costs a few pixels and converts a genre marker into a control. Where space forbids a label, the tooltip and the accessible name have to carry the whole burden, which makes them worth writing carefully rather than filling with the product’s name.

Ambient versus invoked is the other axis. An entry point that waits to be clicked respects the viewer’s attention and gets used less. One that offers itself proactively gets used more and interrupts. Guideline 3 is about exactly this timing, and the workable compromise is usually to stay quiet by default and appear on a signal the viewer generated, like a selection, a pause, or an empty state.

Persistence has a cost that’s easy to underweight. A permanent button occupies a slot in a toolbar forever, and toolbars are the most contested space in any mature product. Attaching the entry point to selection or context rather than to chrome avoids spending that slot, and it keeps the interface from acquiring a control that most sessions never touch.

Use when

The assistant is a feature inside a product people already use for something else.

Don’t use when

The assistant is the product. There the entry point is the whole screen, and a sparkle is decoration on a surface that’s nothing to compete with.

Trade-offs

Contextual entry points are discoverable at the moment of need and invisible the rest of the time, so nobody learns the feature exists until they happen to be in the right place. A persistent global button is always findable and always slightly in the way, and it teaches the wrong model by implying the assistant works the same everywhere. Proactive offers lift adoption and generate the resentment that ambient AI features attract. An icon everyone has adopted carries recognition and no meaning—a poor trade for a control that does something specific.

Checklist

  • Is the entry point next to the object it acts on?
  • Does it carry a verb, or only an icon?
  • What’s its accessible name, and does it describe the action?
  • Does it appear unprompted, and on what signal?
  • Can it be dismissed, and does the dismissal stick?
  • What permanent space does it occupy, and what did that space cost?
  • Is there a keyboard path for people who never use the button?
  • Does it appear in contexts where the assistant cannot help?
  • Does it look the same across the product when it does different things?
  • Can someone who does not want it turn it off?

Compare

Notion puts the entry at the cursor and on selection rather than in the chrome, so invocation happens where the writing is and no toolbar slot is spent. Figma attaches its equivalent to the canvas selection, where the object is a frame and the available actions follow from what is selected. Microsoft Copilot takes the opposite approach with a persistent ribbon presence across applications, buying consistency and constant visibility at the price of a permanent slot in the most contested toolbar in software. Raycast removes the surface entirely and makes the entry point a global keystroke. For anyone who learns it that’s the cheapest invocation there is. For everyone else it may as well not exist.

Inline assist is the most common thing an entry point opens. Assistant sidebar is the heavier destination. Command menu is the keyboard-first alternative to a visible affordance. Prompt starters handle the moment after the entry point is used. Ghost text is the version that needs no entry point at all and carries the costs that come with that.

AI entry point anatomy Three placements compared: a control attached to a text selection, one in a document header, and a permanent button in the global toolbar, with the sparkle icon shown alone and again paired with a verb. Next to the object, or nowhere in particular File Edit View AI Q3 review summarise rewrite this the icon alone says that something is AI, not what it does a permanent button spends the most contested space in the product 1 2 3 4 1 AT THE SELECTION Proximity does the explaining that an icon cannot, and spends no toolbar slot. 2 AT THE DOCUMENT For actions on the whole thing, where the object is the page rather than a passage. 3 IN THE CHROME Always findable, always slightly in the way, and it implies one uniform behaviour. 4 PAIR THE ICON WITH A VERB The sparkle became a genre marker in two years and stopped carrying meaning. Contextual entry points are found at the moment of need and never learned the rest of the time.
Wireframe — the pattern's anatomy, not any one product's version of it

Implementation

A button that sits next to the object it acts on and pairs the sparkle with a verb. The verb and the object are required props, because the icon alone says that something is AI without saying what it does, and the accessible name has to describe the action rather than the brand.

shadcn
npx shadcn@latest add button
npm
lucide-react
Tokens
--card--card-foreground--muted-foreground--border--input--chart-1
FileEditView

Q3 review

Revenue for the quarter came in at £1.84m, three percent ahead of plan, with services carrying most of the beat. Costs were higher than we had budgeted for on account of the fact that hiring ran ahead of the plan in the second half of the quarter. Cash at the end of the period stood at £6.2m.

AiEntryPoint.tsxSparkle plus verb, an accessible name built from the verb and its object, and a placement that marks a selection-attached control as belonging to the passage.

import { Sparkle } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

/**
 * An entry point is a button that sits next to the thing it acts on and says
 * what it does. Both halves are props the caller cannot leave out. `verb`,
 * because the sparkle became a genre marker in about two years and now says
 * that something is AI rather than what it does. `object`, because the
 * accessible name has to describe the action on the thing, and a screen
 * reader hearing the product's name learns nothing.
 *
 * Where it goes is the caller's job, and the point: at the selection for a
 * passage, in the header for the document, beside the table for the data.
 * A permanent slot in the global toolbar is the one placement this component
 * does not offer a style for.
 */
export type Placement = "document" | "selection";

type Props = {
  /** What pressing it does, as an imperative: "summarise", "rewrite this". */
  verb: string;
  /** What it acts on. Only the accessible name carries it; the button beside
   *  the object does not need to repeat what the eye can see. */
  object: string;
  /** "document" waits quietly in the header. "selection" rode in on a signal
   *  the viewer made, so it is marked as belonging to the passage. */
  placement: Placement;
  onInvoke: () => void;
  /** The keyboard path, for people who never reach for the button. */
  shortcut?: string;
};

export function AiEntryPoint({ verb, object, placement, onInvoke, shortcut }: Props) {
  const name = `${verb}: ${object}`;
  return (
    <Button
      variant="outline"
      size="sm"
      onClick={onInvoke}
      aria-label={name}
      aria-keyshortcuts={shortcut}
      title={shortcut ? `${name} (${shortcut})` : name}
      className={cn(
        "h-7 gap-1.5 px-2.5 text-[11px] font-normal",
        placement === "selection" && "border-chart-1 text-chart-1 hover:text-chart-1",
      )}
    >
      <Sparkle className="!size-3 fill-chart-1 text-chart-1" aria-hidden="true" />
      {verb}
    </Button>
  );
}

demo.tsxHow it is called: summarise in the document header, rewrite this at a selected sentence. Rewriting replaces the sentence and takes the control away with the selection.

import { useState } from "react";
import { AiEntryPoint } from "./AiEntryPoint";

/**
 * A document with two entry points, each next to its object. "summarise" waits
 * in the header because its object is the whole page. "rewrite this" appeared
 * because a sentence was selected, and goes away with the selection.
 */
const BEFORE = "Revenue for the quarter came in at £1.84m, three percent ahead of plan, with services carrying most of the beat. ";
const SELECTED = "Costs were higher than we had budgeted for on account of the fact that hiring ran ahead of the plan in the second half of the quarter.";
const AFTER = " Cash at the end of the period stood at £6.2m.";
const REWRITTEN = "Costs ran over budget because hiring outpaced the plan in the second half.";

export default function Demo() {
  const [selected, setSelected] = useState(true);
  const [sentence, setSentence] = useState(SELECTED);
  const [summary, setSummary] = useState<string>();

  const rewrite = () => {
    setSentence(REWRITTEN);
    setSelected(false);
  };

  return (
    <div className="rounded-lg border bg-card">
      <div className="flex gap-5 border-b px-4 py-2.5 text-[11px] text-muted-foreground">
        <span>File</span><span>Edit</span><span>View</span>
      </div>

      <div className="p-4">
        <div className="flex items-center gap-3">
          <h2 className="text-sm font-medium text-card-foreground">Q3 review</h2>
          <AiEntryPoint
            verb="summarise"
            object="Q3 review"
            placement="document"
            shortcut="Meta+J"
            onInvoke={() => setSummary("Revenue £1.84m, 3% over plan. Costs over budget on hiring. Cash £6.2m.")}
          />
        </div>
        {summary && <p className="mt-2 text-xs text-muted-foreground">{summary}</p>}

        <p className="mt-4 text-sm leading-relaxed text-card-foreground">
          {BEFORE}
          <span
            className={selected ? "bg-chart-1/20 text-card-foreground" : undefined}
            onMouseUp={() => setSelected(true)}
          >
            {sentence}
          </span>
          {AFTER}
        </p>

        {selected && (
          <div className="mt-2 flex justify-end">
            <AiEntryPoint
              verb="rewrite this"
              object="the selected sentence"
              placement="selection"
              onInvoke={rewrite}
            />
          </div>
        )}
      </div>
    </div>
  );
}
What it renders. Identical markup in both panes, with only the token values changing.

Examples

No captures reference this pattern yet. Captures arrive product by product; see Products for what's in the gallery so far.