Skip to content
Kura

Browser Session

experimental

A computer/browser-use session made legible: tidy browser frame, the page, the agent's cursor with click ripple and target box, and a step log with take-over.

@kura-ui/react/browser-sessionCopy for agentsMarkdownRegistry JSON

A page with the agent's cursor

minimal
Agent is browsing
github.com/acme/web/pull/482
acme/webCodePull requestsActions

Migrate session API to @acme/auth client #482

Openkura wants to merge 4 commits into main from kura/auth-client
ConversationCommits 4Checks 3Files changed 6
Replaces fetchUser() and the legacy /api/session REST calls with createAuthClient(). Refreshes expired sessions with the rotated token.
All checks have passed
test142 passed · 41s
typecheck0 errors · 18s
lintclean · 6s

Opening the pull request

Kura opens the compare view, types the title and description, clicks “Create pull request” and reads the PR number. The cursor glides, clicks ripple, the log advances and the session settles.

full
Agent is browsing
github.com/acme/web/compare/main...kura/auth-client
acme/webCodePull requestsActions

Open a pull request

Create a new pull request by comparing changes across two branches.

base: main←compare: kura/auth-client Able to merge
Title
Title
Description
Add a description
Markdown is supportedCreate pull request

4 commits · 6 files changed · +142 −38

  1. Open the compare view (in progress)github.com/acme/web/compare/main...kura/auth-clientnavigate
  2. Focus the title field (pending)input#pr-titleclick
  3. Type the PR title (pending)“Migrate session API to @acme/auth client”type
  4. Write the description (pending)“Replaces fetchUser() and the legacy /api/session…”type
  5. Click “Create pull request” (pending)button[type=submit]click
  6. Read the PR number (pending)#482 · Openextract
Open the compare view

Paused for you

A 2FA prompt only the human can answer: amber edge, “Resume agent”.

state
Paused for you
cloud.acme.dev/login/two-factor?next=%2Fweb%2Fdeployments

Two-factor authentication

Enter the 6-digit code from your authenticator app to continue to Acme Cloud.

VerifyUse a recovery code instead
  1. Open the preview (done)cloud.acme.dev/web/deploymentsnavigate
  2. Continue with GitHub (done)button[data-provider="github"]click
  3. Enter the 2FA code (waiting for you)Needs a code only you havetype
  4. Check the login page (pending)/loginextract
Enter the 2FA code, then hand back

Under the plan

A narrow stacked session under a TaskList, as in a run sidebar.

composition
Plan1 of 3
  • Run pnpm test (done)36.8s
  • Open pull request (in progress)via the browser
  • Summarize the run (pending)
Task 2 of 3: Open pull request
Agent is browsing
github.com/acme/web/pull/482
acme/webCodePull requestsActions

Migrate session API to @acme/auth client #482

Openkura wants to merge 4 commits into main from kura/auth-client
ConversationCommits 4Checks 3Files changed 6
Replaces fetchUser() and the legacy /api/session REST calls with createAuthClient(). Refreshes expired sessions with the rotated token.
All checks have passed
test142 passed · 41s
typecheck0 errors · 18s
lintclean · 6s
  1. Click “Create pull request” (done)click
  2. Read the PR number (in progress)h1extract
Read the PR number

Installation

npx shadcn@latest add https://kuro.abstergo.fyi/r/browser-session.json

Copies the source into components/kura/browser-session with its dependencies (kura-theme, button, kura-format, shimmer-text, status-glyph, use-elapsed, utils). Tokens come from the kura-theme item.

When to use it

Use it for

  • Show what a browser-use or computer-use agent is doing on a web page (Operator, Claude computer use, Browserbase, Playwright-driven agents).
  • Stream screenshots of a remote browser (`src`) with the agent's next action drawn on top (`cursor`, `highlight`).
  • Replay a recorded browser run step by step with the log of navigate / click / type / scroll / extract actions.
  • Hand control to the human when the agent hits a login, 2FA or CAPTCHA (`status="paused"` + `onResume`), or let them take over (`onTakeOver`).

Reach for something else when

  • Terminal or shell output from the agent — use terminal.
  • Code edits made by the agent — use diff-view or file-changes.
  • A plan or todo list of the whole run — use task-list.
  • A static rendered artifact (HTML preview, document) — use artifact-card.

Props

PropTypeDefaultDescription
url*string—Page URL in the address bar. The host is emphasised, the path muted; https shows a lock.
titlestring—Page title next to the address bar (hidden in narrow containers).
childrenReact.ReactNode—Viewport content: a live page, or a mock rendered as markup.
srcstring—A screenshot URL to show instead of children (e.g. the latest frame from a remote browser).
altstring—Alt text for `src`. Default “Screenshot of {url}”.
viewport{ width: number; height: number }—Design size of the page in CSS px (e.g. the agent's 1280×800 screen). Children render at this size and scale to fit the frame, so % coordinates stay exact at any width. Omit to let children flow at the frame's width.
aspectRationumber16 / 10Viewport aspect ratio when `viewport` is not given.
scrollTopnumber0Vertical page scroll in viewport px; eases on change (use for scroll steps).
cursorBrowserPoint | null—The agent's cursor { x, y } in % of the viewport. Glides to new positions.
cursorLabelstring—Name tag on the cursor, e.g. the agent's name.
clickKeystring | number—Change it to play a click ripple at the cursor. Default: the active step's id when that step is a click.
highlightBrowserHighlight | null—Box around the target element: { x, y, width, height } in % plus an optional `label` tag (e.g. `button "Create pull request"`).
stepsreadonly BrowserStep[]—The action log. BrowserStep = { id, kind: "navigate" | "click" | "type" | "scroll" | "extract", label, status: AgentStatus, detail? (mono: URL, selector, typed text) }. Omit to hide the log.
activeStepstring—Id of the step being executed. Default: the first running step.
status"browsing" | "paused" | "done" | "failed""browsing"browsing = “Agent is browsing” (blue, shimmer); paused = “Paused for you” (amber, the viewport gets an amber edge); done; failed.
statusTextReact.ReactNode—Secondary text after the status, e.g. “Enter the 2FA code, then hand back”.
startedAtDate | number—Session start (wall clock) for the elapsed clock; ticks while browsing.
loadingboolean—Show the loading bar under the address bar. Default: true while the active step is a running navigate.
actionsReact.ReactNode—Extra controls in the status line (e.g. open in new tab, replay).
onTakeOver() => void—Shows a “Take over” button while browsing.
onResume() => void—Shows a “Resume agent” button while paused.
layout"auto" | "side" | "stacked""auto"Step log beside the browser (side), below it (stacked), or beside only when the container is ≥ 48rem (auto).

All native attributes of the root element, className and ref pass through.

Anatomy

  1. BrowserSessionRoot panel; `data-status`, `data-layout`; container-query context; polite status region.data-slot="browser-session"
  2. HeaderStatus line: glyph, “Agent is browsing” / “Paused for you”, statusText, done/total, elapsed, actions, Take over / Resume.data-slot="browser-session-header"
  3. ElapsedMono clock from startedAt.data-slot="browser-session-elapsed"
  4. BrowserColumn with the chrome and the viewport.data-slot="browser-session-browser"
  5. ChromeTitle (favicon letter + text) and the address bar.data-slot="browser-session-chrome"
  6. Addressrole="group" “Address”: lock, host, muted path, in mono.data-slot="browser-session-address"
  7. Loading2px accent sweep under the chrome while a page loads.data-slot="browser-session-loading"
  8. ViewportFixed-aspect frame (no layout shift); amber inner edge while paused.data-slot="browser-session-viewport"
  9. PageHolds children/src; scaled to fit when `viewport` is set; translated by scrollTop.data-slot="browser-session-page"
  10. Overlayaria-hidden layer for the highlight, ripple and cursor.data-slot="browser-session-overlay"
  11. HighlightAccent box + mono tag around the target; eases between targets.data-slot="browser-session-highlight"
  12. CursorPointer arrow with an optional accent name tag; glides between points.data-slot="browser-session-cursor"
  13. RippleAccent ring that expands and fades after the cursor arrives.data-slot="browser-session-ripple"
  14. LogScrollable step log; keeps the active step in view.data-slot="browser-session-log"
  15. Step<li> with `data-kind`, `data-status`, `data-active`; aria-current="step" on the active one.data-slot="browser-session-step"

Accessibility

  • The overlay (cursor, ripple, highlight) is decorative and aria-hidden; what the agent is doing is carried by the step log and the status line.
  • The step log is an <ol> labelled “Browser actions”; each step speaks its status after the label, and the active one has aria-current="step".
  • A polite status region announces the active step's label (when it is a string), “Paused for you” / your statusText, “Session ended” or “Session failed” — never the ticking clock.
  • The address bar is a labelled group; the lock icon is labelled “Secure connection”. With `src`, the image gets alt text (default “Screenshot of {url}”).
  • Take over / Resume agent are real buttons with visible focus. Paused state is signalled by text and glyph, not only the amber edge.
  • Reduced motion: The cursor and highlight jump instead of gliding (the highlight still fades), the click ripple is skipped, page scroll is instant, the loading sweep becomes a static bar and the shimmer stops.
KeysAction
TabMoves to the status-line actions (Take over / Resume agent) and any controls inside the page.

Notes for agents

  • Coordinates are percentages of the viewport. If your agent reports pixels on a W×H screen, pass `viewport={{ width: W, height: H }}` and use x = px / W * 100.
  • For remote browsers pass the latest screenshot as `src` and keep `viewport` equal to the screenshot size; draw the *next* action with `cursor` + `highlight`.
  • Change `clickKey` (e.g. an action counter) to replay the ripple; repeated clicks on the same step otherwise only ripple once.
  • Set `status="paused"` whenever the agent needs the human (login, 2FA, CAPTCHA, payment) and say why in `statusText`.
  • Map the agent's actions to the five kinds; put the URL, selector or typed text in `detail` (mono).