Xzero UI
Pro library

Agent statusPro

A compact live status pill for a running AI agent: the agent's mark in a live ring, the current activity and an elapsed timer, opening into the steps so far.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/agent-status
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui-pro/agent-status

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { AgentStatus } from "@/components/xzero/agent-status/agent-status";
import { FileSearch, FilePen, FlaskConical } from "lucide-react";

export function RunHeader({ run, agent }) {
  return (
    <AgentStatus
      status={run.status}               // "working" | "needs-input" | "paused" | "done" | ...
      startedAt={run.startedAt}
      agent={{ name: "Claude Sonnet 5.5", mark: <ClaudeMark style={{ color: "#D97757" }} /> }}
      activity={{ label: "Running tests", icon: FlaskConical, progress: { value: 8, total: 12 } }}
      steps={[
        { id: "read", label: "Read 12 files", icon: FileSearch, status: "done", durationMs: 1900 },
        { id: "edit", label: "Edited src/billing/invoice.ts", icon: FilePen, status: "done", durationMs: 2500 },
        { id: "tests", label: "Running tests", icon: FlaskConical, status: "active", startedAt: run.stepStartedAt },
        { id: "push", label: "Push the branch", status: "pending" },
      ]}
      onPause={() => agent.pause(run.id)}
      onResume={() => agent.resume(run.id)}
      onStop={() => agent.cancel(run.id)}
      onApprove={() => agent.approve(run.id)}
      onDeny={() => agent.deny(run.id)}
      onRetry={() => agent.retry(run.id)}
      onOpenRun={() => router.push(`/runs/${run.id}`)}
    />
  );
}

// With no props it plays the simulated coding run.
<AgentStatus />

API reference

AgentStatus

A compact live status pill for a running AI agent, made for an app header or the space above a composer. Collapsed it shows the agent's mark inside a thin live ring, the current activity with a matching icon, and an elapsed timer in tabular numerals. Each new activity rolls in from below while the pill's width follows on a spring. A click expands the pill in place into a small floating panel with the latest steps (icon, text, duration), a thin step progress bar and Pause, Stop and Open run controls; Escape or a press outside closes it. It covers idle (Ready), working, needs input (an accent dot with inline Approve and Deny), paused, done (the ring closes and the mark morphs into a check, then it settles back to Ready), failed (with Retry) and stopped. With no props it plays a simulated coding run.

PropTypeDefaultDescription
status"idle" | "working" | "needs-input" | "paused" | "done" | "failed" | "stopped"–The run's state. Leave it out to play the built in simulated coding run (Claude Sonnet 5.5) with working controls.
activity{ label: string; icon?: AgentIcon; progress?: { value: number; total: number } }–What the agent is doing now, in the present tense ("Reading 12 files", "Editing src/billing/invoice.ts"). The icon rolls in with the label. Progress ticks in place as "8 of 12" without rolling the label. In needs input it is the request ("Needs your approval to run git push"), in done the outcome appended to "Done in 1m 12s" ("6 files changed"), and in failed the failure ("Tests failed · 2 errors").
stepsAgentStep[][]Every step of the run, pending ones included so the progress bar knows the total. Each step has id, label, optional icon, status ("pending" | "active" | "waiting" | "done" | "failed" | "skipped"), startedAt for a live step and durationMs for a finished one. Write active labels in the present tense and finished ones in the past tense ("Running tests" then "Passed 12 of 12 tests"), so the text itself carries the status.
startedAtnumber | Date–When the run started. The timer counts from here and leaves out time spent paused or failed, so it never jumps when the run resumes.
endedAtnumber | Date–When the run ended. Defaults to the moment the status turned done or stopped.
agent{ name: string; mark?: ReactNode }{ name: "Agent" }The model or agent and its brand mark, drawn at 12px inside the live ring. Give a mono mark its brand color, for example the Claude mark in #D97757.
onPause() => void–Shows Pause in the panel while working.
onResume() => void–Shows Resume in the panel while paused. Pause and Resume share one button, so focus stays put.
onStop() => void–Shows Stop in the panel while working or paused.
onApprove() => void–Shows Approve in the accent color, inline in the pill and in the panel, while the status is needs-input.
onDeny() => void–Shows Deny next to Approve while the status is needs-input.
onRetry() => void–Shows Retry in the accent color, inline and in the panel, when the run failed.
onOpenRun() => void–Shows an Open run button in the panel for a full log or trace view. It confirms with a check for a moment after it is pressed.
settleAfternumber | null4000Milliseconds after done or stopped before the pill settles back to Ready. The panel keeps the last run's steps. Null keeps the result on screen.
align"start" | "center" | "end""center"Which edge the panel grows from. Use start or end when the pill sits against a header edge.
expandedboolean–Controls the panel. Pair with onExpandedChange.
defaultExpandedbooleanfalseOpens the panel on first render when uncontrolled.
onExpandedChange(expanded: boolean) => void–Called when the pill is pressed, Escape is pressed or a press lands outside the open panel.
maxStepsnumber5How many of the latest steps the panel lists. Older steps slide out at the top as new ones arrive.
noticestring–A one-off message for screen readers, such as the result of an action. It joins the automatic status announcement.
classNamestring–Class on the root element.

useAgentRunSimulation

The scripted runs behind the preview, exported for prototypes and tests. Returns every AgentStatus prop for a run plus replay(). Nothing runs for real: approvals, pushes, searches and Open run only update local state and say so through notice.

PropTypeDefaultDescription
scenarioId"coding" | "research""coding"Coding is Claude Sonnet 5.5 fixing a proration bug, ending on an approval to run git push. Research is Gemini 4 Argon comparing vendor pricing; one fetch times out on the first try so Retry can be seen.
startDelaynumber900Milliseconds of Ready before the run starts.

Keyboard interactions

KeysAction
TabMoves to the pill, then to the inline Deny and Approve or Retry buttons when they show. With the panel open, Tab moves through Pause or Resume, Stop or Deny, and Open run.
Enter, SpaceOn the pill, opens or closes the panel. On a button, activates it.
EscapeCloses the panel from anywhere inside it and returns focus to the pill.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in ai

Guidance for AI tools

Agent status: A compact live status pill for a running AI agent: the agent's mark in a live ring, the current activity and an elapsed timer, opening into the steps so far. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components