# 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.

- Type: Component (special)
- Access: Arc Pro
- Page: https://uiarc.dev/components/agent-status
- Markdown: https://uiarc.dev/components/agent-status/markdown
- Source file: `registry/components/agent-status/agent-status.tsx`
- Dependencies: motion, lucide-react
- Keywords: special, motion, ai, new, agent status, ai agent, status pill, run status, live indicator, approval, human in the loop, coding agent, research agent, elapsed timer, progress, dynamic island, agent run, claude, tool calls

## When to use

- An app header, title bar or composer that needs to show at a glance that an agent is running, what it is doing and for how long.
- Coding, research or browser agents that pause for approval, so the person can approve or deny without opening a full run view.
- Background runs that people check on occasionally: the pill stays small, and the panel shows recent steps and controls on demand.

## When not to use

- Use agent-run or research-run when the run itself is the page and every step, tool call and output needs room.
- Use agent-approvals to review a queue of pending approvals across several agents.
- Use agent-orchestrator or agent-tasks to compare many agents or runs at once.
- Use text-shimmer alone for a single inline working label without a timer, steps or controls.

## Installation

Agent status is part of Arc Pro. The live preview is public; the source and install command need Pro.

### CLI with a Pro token

1. Create a token in your account and set it in the environment (or `.env.local`). Never commit it.

```bash
export ARC_PRO_TOKEN=arc_pro_...
```

2. Add the Pro registry to `components.json`:

```json
{
  "registries": {
    "@uiarc": "https://uiarc.dev/r/{name}.json",
    "@uiarc-pro": {
      "url": "https://uiarc.dev/r/pro/{name}.json",
      "headers": {
        "Authorization": "Bearer ${ARC_PRO_TOKEN}"
      }
    }
  }
}
```

3. Install:

```bash
npx shadcn@latest add @uiarc-pro/agent-status
```

### Manual

Signed-in Pro members can copy the source from the Manual tab on the docs page.

- Plans: https://uiarc.dev/pricing
- Create a Pro token: https://uiarc.dev/account#pro-access
- Setup guide: https://uiarc.dev/docs/ai#pro-access

## Usage

```tsx
import { AgentStatus } from "@/components/arc/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.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `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"). |
| `steps` | `AgentStep[]` | `[]` | 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. |
| `startedAt` | `number \| 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. |
| `endedAt` | `number \| 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. |
| `settleAfter` | `number \| null` | `4000` | Milliseconds 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. |
| `expanded` | `boolean` | – | Controls the panel. Pair with onExpandedChange. |
| `defaultExpanded` | `boolean` | `false` | Opens 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. |
| `maxSteps` | `number` | `5` | How many of the latest steps the panel lists. Older steps slide out at the top as new ones arrive. |
| `notice` | `string` | – | A one-off message for screen readers, such as the result of an action. It joins the automatic status announcement. |
| `className` | `string` | – | 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.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `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. |
| `startDelay` | `number` | `900` | Milliseconds of Ready before the run starts. |

## Keyboard interactions

| Keys | Action |
| --- | --- |
| Tab | Moves 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, Space | On the pill, opens or closes the panel. On a button, activates it. |
| Escape | Closes the panel from anywhere inside it and returns focus to the pill. |

## Accessibility

- The pill is a button with aria-expanded and aria-controls pointing at the panel, and an accessible name that reads the agent, the activity, the count and the elapsed time.
- A polite status region announces each new activity and the outcome ("Claude Sonnet 5.5: done in 14 seconds, 6 files changed"), not every tick of a count or the timer. Pass notice to add the result of an action.
- Status never relies on color: every state pairs the ring and glyph with words (Ready, Paused, Needs your approval, Done in, Failed, Stopped after), and steps use present tense while running and past tense once finished.
- The step progress bar is a progressbar with a value text such as "4 of 6 steps finished".
- Pause and Resume, and Approve and the Pause that follows it, share one button, so keyboard focus stays in place. If a focused control disappears with a state change, focus moves to the pill instead of the page.
- In narrow containers the inline Approve, Deny and Retry and the Open run button become icon buttons with accessible names. A truncated activity stays readable in full through the pill's name and the panel's step list.
- Pointer focus draws no ring; keyboard focus shows Arc's shared focus ring, inset on the pill.

## Motion

- A new activity rolls in vertically in about 180ms while the old one leaves upward; the pill's width follows on the morph spring, and the label fades at its right edge only while it is wider than its room, so nothing snaps or wraps.
- Opening the panel springs width and height together on the smooth spring from the pill's own footprint; the header row stays where it is and the panel content fades in after a beat. Closing reverses it with a faster fade.
- The live ring spins a short arc while working, freezes in place when paused, gives way to an accent dot with one soft ping when input is needed, and closes around the glyph as the mark morphs into a drawn check (done) or cross (failed).
- The working label carries a calm shimmer that stops in every other state. Counts and the timer change in place with tabular numerals.
- New steps fade in at the bottom of the panel while older ones slide up; segments of the progress bar fill from the left.
- Reduced motion swaps every spring for an instant change, drops the roll, the spin, the ping and the shimmer, and keeps all states, text, focus and announcements.

## Responsive behavior

- The pill sizes to its content and never exceeds its parent's width; a long activity fades out at its right edge instead of wrapping.
- Below 400px of available width the inline actions become icon buttons, the timer steps aside while they show, and Open run in the panel becomes an icon button.
- The panel opens at 384px or the pill's width, whichever is wider, capped by the parent, and floats over the page with a shadow so nothing below moves.
- Step labels in the panel wrap rather than truncate, so long file paths stay readable on a phone.

## Performance

- The timer runs on a small per-instance clock that ticks four times a second only while the run is live and stops when paused, done or idle.
- Width and height animate motion values directly; natural widths come from two hidden, inert measuring rows watched by a ResizeObserver, so the pill never measures in the middle of an animation.
- The spinner and shimmer are CSS animations that pause or stop outside the working state.

## Notes for AI

- Drive it from your agent's event stream: set status, keep activity to the latest tool call or phase in the present tense, and append steps as they finish. Keep the pill's label short; the panel carries the history.
- Keep startedAt fixed for the whole run; the component freezes paused and failed time itself. Pass endedAt from your backend when you have it.
- Use needs-input for any approval gate (shell commands, pushes, payments, emails) and phrase activity.label as the request: "Needs your approval to run git push".
- For done, put only the outcome in activity.label ("6 files changed"); the component writes "Done in 1m 12s · 6 files changed".
- Pass only the handlers your backend supports; each control appears only when its handler exists.
- Place it in a container that sets its width, such as a header slot or a flex row: the pill measures its parent to truncate cleanly and to size the panel.

## Related

- [Agent run](https://uiarc.dev/components/blocks/agent-run/markdown): A single card that follows one AI coding agent through a task: steps stream in with the live one shimmering, tool calls open in place, and the agent stops on a two-file diff for you to approve or send back before it writes. When the run ends, the steps fold into one line and a result shows the files changed, the checks that passed and a pull request button.
- [Agent approvals](https://uiarc.dev/components/blocks/agent-approvals/markdown): One approval card for agents: the waiting tool call reads like a permission prompt with the tool's mark, the agent's reason and its arguments, and you approve, deny or allow it from now on.
- [AI composer](https://uiarc.dev/components/blocks/ai-composer/markdown): The prompt box at the bottom of an AI app: files upload in place, / opens commands, @ inserts mentions, a model and effort menu sits in the toolbar, and the send button turns into a stop control ringed by the reply's progress.
- [Tool call](https://uiarc.dev/components/tool-call/markdown): A tool call row for agent transcripts: the tool's mark and the call in plain words, a live state while it runs, and the input and output a click away, with approval and retry when needed.
- [Agent plan](https://uiarc.dev/components/agent-plan/markdown): The plan an agent writes before it acts: edit, reorder or add steps while it is a draft, then watch it work through them as a live checklist.
- [Text shimmer](https://uiarc.dev/components/text-shimmer/markdown): Show ongoing work with a calm light across the words.

## Also in ai

- [Agent timeline](https://uiarc.dev/components/agent-timeline/markdown): A compact timeline of one orchestrated agent run: the orchestrator and its subagents share a time axis, handoffs draw in between rows, and a playhead replays thinking, tool calls and waiting while the header counts time, tokens and cost. Hover a span for what it did, or click it to trace its handoff path.
- [Context window](https://uiarc.dev/components/context-window/markdown): An AI context window as a grid of 200 cells: the system prompt, tools, files, summary and messages fill it in order, a threshold row marks where compaction starts, and sending a message, attaching a file or compacting shows exactly how much still fits.

## 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://uiarc.dev/llms.txt
