PixelDosa UI

Agent Console

The screen you come back to — what changed while you were away, then every run grouped by what it needs.

Agents

2 waiting on you · 1 stopped with a problem · 1 finished

Start with the refund — it has been waiting three hours.

Since yesterday at 18:00

Runs

2 waiting on you · 6 in total

Needs you2

  • Outside the policy window. I can't decide this one.

    Support agent · Waiting 3 hours

  • Two contacts look like duplicates. Merge them?

    Finance agent · Waiting 40 minutes

Working1

  • Reading 12 of 30 sources

    Research agent · Started 6 minutes ago

Stopped with a problem1

  • The CMS rejected two updates. Nothing was published.

    Content agent · Stopped an hour ago

Finished1

  • 24 drafted, 0 sent. All waiting on your review.

    Support agent · Finished at 09:14

Scheduled1

  • Research agent · Monday at 07:00

Triage the support inbox

3 of 4 doneWaiting on you

  1. Read the overnight conversations

    Done30 read

  2. Group them by what they need

    Done24 need a reply

  3. Draft a reply for each

    Done24 drafted

  4. Send the replies

    Waiting for youWaiting for your review — nothing has been sent.

Waiting for you.

What happened

  1. 09:02

    System · Started the run

    Allowed by: Schedule set by Dana

  2. 09:04

    Agent · Read 30 support conversations

    Allowed by: Autonomy: acts on low-risk changesResult: 24 needed a reply

  3. 09:11

    Agent · Drafted 24 replies

    Allowed by: Autonomy: acts on low-risk changesResult: Held for review, none sent

  4. 09:14

    Agent · Stopped before sending

    Allowed by: Sending needs your approval

When this agent runs

2 of 3 on

  • Every weekday at 9:00

    Triages the support inbox and drafts replies

    Next: Tomorrow at 9:00Ran today · 24 drafted, 0 sentStops to ask you

  • When an invoice arrives from a new supplier

    Checks it against the purchase order and flags mismatches

    Next: Whenever one arrives

  • Every Monday at 7:00

    Sends the weekly competitor digest to the team

    Failed last Monday · the source feed timed out

Installation

bash
npx shadcn@latest add @pixeldosa/agent-console

Requires `cn` at `@/lib/utils`. Write `briefing.nextUp` as the one thing worth doing first, not a summary — it is the sentence that has to survive being read on a phone at a bus stop. Times and counts are formatted by you.

Usage

"use client";

import { AgentConsole } from "@/components/blocks/agent-console";

<AgentConsole
  briefing={{
    since: "yesterday at 18:00",
    needsYou: 2,
    finished: 1,
    failed: 1,
    nextUp: "Start with the refund — it has been waiting three hours.",
  }}
  runs={runs}
  selectedId={selected}
  onSelect={setSelected}
  detail={detail}
  triggers={schedules}
  onTriggerEnabledChange={toggle}
/>

Why it exists

People hand a job to an agent, close the laptop, and come back later. Two products shipped a surface for exactly that this year, replacing "the agent's work lives in a chat thread you have to find" with a place designed to be returned to.

The part still treated as an afterthought is the return itself. Research on agentic interfaces puts it plainly: the moment someone comes back after four hours is where trust is won or lost, and it should read as a briefing — what happened, what needs you, what to do next — rather than a pile the person has to reconstruct that from.

Features

  • The briefing comes first, in words: what changed since you were last here, and the one thing worth doing first. It turns the waiting colour only when something genuinely needs a person.
  • Zero is stated. "Nothing changed while you were away" is a useful answer; an empty space isn't.
  • The inbox groups by need, not time, so a run that's been waiting three hours can't sit below one that finished a minute ago.
  • The detail answers the two real questions: where did it get to (the plan), and who let it do that (the trail, with its authority field).
  • A person being involved comes first. When a run is waiting for someone, the handoff sits above the agent's own account of itself.
  • What runs on its own is on the same screen, as sentences rather than cron.

Props

PropTypeNotes
briefing{ since?, needsYou, finished, failed, nextUp? }The return moment. Counts are numbers; nextUp is your sentence.
runsAgentRun[]Everything Run Inbox takes.
selectedId / onSelectstring / (id) => voidonSelect required. The matching row is marked with aria-current.
detailConsoleRunDetail | nullThe selected run: steps, trail, handoff.
onStopRun / onStopSelected(id) => void / () => void
onRetryStep(stepId) => voidOn a failed step.
onUndo / onExportTrail(entryId) => void / () => voidOn the trail.
onTakeOver / onReturnToAgent() => voidOn the handoff.
triggers / onTriggerEnabledChangeScheduleTrigger[] / (id, enabled) => voidLeave out to hide the schedule entirely.
detailEmptyLabel / inboxEmptyLabelstring
headingLevel2 | 3 | 4Defaults to 2.

ConsoleRunDetail is { id, title, steps?, runStatus?, trail?, handoff? }, where handoff is { stage, reason?, context?, person?, waitingFor? }.

Accessibility

  • One labelled section; every part inside carries its own heading one level below it, so the outline never skips.
  • The open run is marked with aria-current as well as a background, so the pairing between list and detail doesn't depend on colour.
  • Only genuinely running things animate — a running row's dot, a running step's mark. The briefing never animates; a summary that moves reads as still arriving.
  • Everything stops under prefers-reduced-motion, and each state is also in words.

When not to use

  • One agent run inside a chat: use Thinking Experience.
  • The steps of a single run, on their own: Agent Plan.
  • A notification feed: this is a work queue, not an activity stream.

Notes

Write nextUp as the one thing worth doing first, not a summary. It's the sentence that has to survive being read on a phone at a bus stop.

why it's built this way

Engineering Notes

The briefing sits above everything and is written in words rather than badges, because the failure of a returned-to surface is that it hands back a pile and makes the person do the triage that the system already has the data to do. It turns the waiting colour only when something actually needs a person, so the colour means the same thing here as it does on a single approval. Zero is stated rather than hidden: 'Nothing changed while you were away' is a useful answer, and an empty space is not. The two-pane split puts the inbox at a fixed width and the detail fluid, because the detail is where the reading happens; the selected row is marked with `aria-current` as well as a background, so the pairing survives without colour. A person being involved is rendered above the machine's account of itself — the handoff comes before the plan and the trail — since a run waiting on somebody is not primarily a story about what the agent did.

how it moves, and when it doesn't

Motion Notes

Motion means the machine is busy, and a console is where that rule earns its keep: on a screen showing six runs, a plan, a trail and three schedules at once, only genuinely running things move — a running row's dot, a running step's mark. Everything waiting on a person is completely still in the waiting colour, so the eye lands on the one place work is actually happening and the stillness of everything else is itself information. The briefing never animates; a summary that moves reads as still arriving. Under `prefers-reduced-motion` every part of that stops and each state is carried by colour, position and words.