Skip to content

Components / Sections

Agent Run

An AI agent's run, replayed in the page: the task at the top, then four lanes that fill in order (the plan ticks off, tool calls spin and finish with their time, a diff writes in line by line, a person is asked to approve and the approve reads Approved), then the result with its numbers. The server HTML is the end state, so without JavaScript and under reduced motion every lane is filled; the animation only plays the path to it, once, in 8 to 12 s. A native checkbox drawn as a small Pause button holds the run, and so does a pointer over it. Zero JavaScript of its own; replay adds a button with a small script.

Live demo

Sample run

One task, from the failing test to the merge

An imaginary agent on an imaginary repository. The lanes fill in order; under reduced motion, or without JavaScript, they are filled from the start.

Task Fix the failing checkout test in apps/web

Done

  1. Plan

    • Read the failing job
    • Reproduce it locally
    • Round the total to cents
    • Run the suite again
  2. Tools

    • read_log(job 4182)done0.4 s
    • grep("toBe(19.99)" apps/web)done0.2 s
    • run_tests(apps/web)done38 s
  3. Changes

    apps/web/src/cart/total.ts
    export function total(items: Item[]) { const sum = items.reduce(add, 0); return sum * 1.2; const gross = sum * 1.2; return Math.round(gross * 100) / 100;}
  4. Review

    Maya Kim

    Ready to merge. The suite passes and the change is two lines.

    Approved

Checkout totals round to cents

Files
1 changed
Tests
48 passed
Time
2 min 41 s
Tokens
18.2k

Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.

Variants · each row writes the attribute the prop writes; the section's own CSS answers

tone
density

Measured

JavaScript of its own

0 B

Uses Reveal and the shared runtime (1.9 kB raw, once per site). With those included: 3.0 kB raw.

With replay: 324 B raw of its own on Reveal and the runtime, measured on its own fixture. The default above ships none of it.

CSS 21.9 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.

Browser support

Baseline · widely available

Chrome 105 · Firefox 121 · Safari 15.4; needs has. Elsewhere: without :has() the run plays once in view and cannot be held; it still ends on the filled lanes.

Install Pro

The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:

terminal
npx shadcn@latest add @moonarc-pro/agent-run
src/pages/index.astro
---
import AgentRun from '@/components/moonarc/pro/AgentRun.astro';
---
<AgentRun
  headline="Watch a run from task to merge"
  task="Fix the failing checkout test in apps/web"
  steps={{
    items: ['Read the failing job', 'Find the cause', 'Change the code', 'Run the tests again'],
    calls: [
      { name: 'read_log', args: 'job 4182', took: '0.4 s' },
      { name: 'run_tests', args: 'apps/web', took: '38 s' },
    ],
    diff: {
      path: 'apps/web/src/cart.ts',
      lines: [
        { kind: 'del', text: 'return total * 100;' },
        { kind: 'add', text: 'return Math.round(total * 100);' },
      ],
    },
    review: { who: 'Maya Kim', note: 'Ready to merge. 48 tests pass.' },
  }}
  result={{ title: 'Checkout total rounds to cents', stats: [{ label: 'Tests', value: '48 passed' }, { label: 'Time', value: '2 min 41 s' }] }}
  replay
/>

Without a key the registry answers 401 with an upgrade message. Everything this section composes is free: reveal.

Props

PropTypeDefaultDescription
taskstringnoneThe task the run is for, in a person's words, at the top of the run.
steps{ items, calls, diff, review }noneThe four lanes. items: the plan, three to five lines. calls: two to four tool calls, { name, args?, took? }, printed as name(args) in the monospace face with the time taken. diff: { path, lines: { kind: 'add' | 'del' | 'ctx', text }[] }, two to eight lines. review: { who, note?, avatar? }: who is asked (their initials are drawn unless avatar is an image URL) and what the agent says to them.
result{ title, stats? }noneThe end of the run: what changed, and numbers such as tests passed, time and tokens, each { label, value }.
headlinestringnoneThe headline above the run. The headline slot wins over it.
eyebrowstringnoneSmall label above the headline. The eyebrow slot wins over it.
copystringnoneThe paragraph under the headline. The copy slot wins over it.
lanes{ plan?, tools?, changes?, review? }Plan · Tools · Changes · ReviewThe four lane titles.
labels{ task?, running?, done?, call?, approve?, approved?, replay? }Task · Running · Done · done · Approve · Approved · ReplayThe words the run prints around its content: the task's label, the status while it runs and once it is done, what a screen reader hears after each finished call, the approve before and after it is pressed, and the replay button.
pauseLabelstring'Pause'The pause control's label: a checkbox drawn as a small button, checked while the run is held.
replaybooleanfalseA button that plays the run again from its first beat: an internal script, measured on its own fixture. Hidden without JavaScript and under reduced motion.
level1 | 22Heading level of the headline: 2 under the page's h1, 1 when the section opens the page. The lane titles sit one level under it.
tone'surface' | 'muted' | 'ink' | 'brand'unset (paints nothing)The ground: the page surface, a muted band, an always-dark ink panel, or a deep brand panel. With theme.css the run's panel takes the tone's card. On brand what is live is marked in the text colour, since the accent is the ground.
density'compact' | 'cozy' | 'roomy''cozy'Block padding and the gap above the run ×0.8 / ×1 / ×1.25 through --ma-density.

Theming and overrides

The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.

Classes

.ma-agent-run.ma-agent-run__approve.ma-agent-run__approved.ma-agent-run__args.ma-agent-run__aside.ma-agent-run__ask.ma-agent-run__avatar.ma-agent-run__bars.ma-agent-run__beat.ma-agent-run__call.ma-agent-run__calls.ma-agent-run__check.ma-agent-run__code.ma-agent-run__controls.ma-agent-run__copy.ma-agent-run__cue.ma-agent-run__decision.ma-agent-run__diff.ma-agent-run__done.ma-agent-run__dot.ma-agent-run__draw.ma-agent-run__eyebrow.ma-agent-run__fn.ma-agent-run__head.ma-agent-run__headline.ma-agent-run__inner.ma-agent-run__item.ma-agent-run__items.ma-agent-run__lane.ma-agent-run__lane-title.ma-agent-run__lanes.ma-agent-run__line.ma-agent-run__live.ma-agent-run__mark.ma-agent-run__note.ma-agent-run__ok.ma-agent-run__path.ma-agent-run__pause.ma-agent-run__pause-control.ma-agent-run__pause-icon.ma-agent-run__pip.ma-agent-run__play.ma-agent-run__replay.ma-agent-run__result.ma-agent-run__result-title.ma-agent-run__ring.ma-agent-run__run.ma-agent-run__running.ma-agent-run__scroll.ma-agent-run__sign.ma-agent-run__spin.ma-agent-run__state.ma-agent-run__stats.ma-agent-run__status.ma-agent-run__task.ma-agent-run__task-label.ma-agent-run__task-text.ma-agent-run__tick.ma-agent-run__took.ma-agent-run__top.ma-agent-run__who.ma-in

Slots

slot="eyebrow"slot="headline"slot="copy"slot="aside"

Reduced motion

The end state at once: every lane filled, every call done, the diff written, the approval given, the result shown. Nothing travels and the controls are not drawn.

With ClientRouter

CSS only (the replay button's script rebinds through the shared runtime). A new page starts a new run when it comes into view.

Why it is built this way

Replaces: Agent plan and tool call demo (Aceternity) · AI workflow animation (Magic UI). See the migration table.

Entrance on scroll that plays once and stays, staggers its children, scrubs with the scroll position when asked, honours reduced motion, and keeps working after every ClientRouter navigation.

every browserscroll

Sample conversation

Ask, watch it work, approve

An imaginary agent on an imaginary repository. Open a call to read what it returned.

Sample agent

Done

  1. You

    Fix the failing checkout test in apps/web

  2. Sample agent

    One assertion fails: the total keeps a fraction of a cent. I will find where it is computed.

    • read_log(job 4182)0.4 s
      FAIL apps/web/cart.test.ts
        total > rounds to cents
        expected 23.99, received 23.988
    • grep("* 1.2" apps/web/src)0.2 s
      apps/web/src/cart/total.ts:3  return sum * 1.2;
    • run_tests(apps/web)38 s
      Tests  48 passed (48)
      Time   37.9 s
  3. Sample agent

    Push the change to fix/checkout-rounding and open a pull request?

    Approved

  4. Sample agent

    Done. The total now rounds to cents after tax, and all 48 tests in apps/web pass. The pull request is open for review.

A conversation with an AI agent, replayed in the page: the reader's message, the agent's reply with its tool calls folded into <details> (the call and its result in the monospace face), a request for approval that is approved, and the final answer, typed, with a button that copies it; a prompt box at the foot as a demo form.

Chrome 116 · not Firefox · Safari 18scrollhoverclick

A hero whose entry point is a prompt box: a small label, a short headline, a lead, a large PromptInput with Enter to send, a status line and example tasks.

newly · Chrome 123 · Firefox 152 · Safari 26.2load

A vertical timeline: the line draws itself down the page in step with the scroll, each step revealing from the line's side as it is reached, markers numbered or dated.

Chrome 115 · not Firefox · Safari 26scroll

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown