Marble UI
← Components

Agent Inbox / Decision Inbox

Preview: Board

All background agent tasks in one place, grouped by what they need from you. A task's title opens it (`onOpen`) in both views.

Import

import { AgentInbox } from '@marbleui/ui'

Props

<AgentInbox>

PropTypeDefaultDescription
tasks *requiredAgentTask[]—
classNamestring—
onOpen(id: string) => void—
onViewChange(v: 'board' | 'list') => void—
view'board' | 'list''board'

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitive: React Aria Button. Follow the primitive's docs for the full keyboard map.

Usage notes

Background agent tasks grouped into Needs you, Running and Done, as a board or a list. For one task’s steps use AgentPlan.

<AgentInbox
  tasks={[
    { id: 'mig', title: 'Migrate users table', state: 'needs-you', meta: 'Waiting for you', actions: <Button size="sm" onPress={() => approve('mig')}>Approve</Button> },
    { id: 'pr', title: 'Review PR #482', state: 'running', meta: '3m 41s', counts: { tools: 12, files: 21 } },
  ]}
  view={view} onViewChange={setView} onOpen={openTask}
/>
  • view is controlled; the Board/List toggle appears only when onViewChange is set.
  • actions are yours to render and handle. Tasks move between groups only when you change their state.
  • With onOpen, the task title is a button in both views; without it the title is plain text.
  • The board is always three columns, so use view="list" in narrow spaces. Tool and file counts show as ⚙/✎ glyphs and are read as “N tool calls” and “N files”; the header badge reads “N need you”.
Example source · show
import { useState } from 'react'
import { Button } from '../button'
import { AgentInbox, type AgentTask } from './agent-inbox'

const actions = <><Button size="sm" variant="ghost">Reject</Button><Button size="sm">Approve</Button></>
const tasks: AgentTask[] = [
  { id: '1', title: 'Migrate users table', summary: 'Split users into accounts and profiles on Postgres 17. The dry run passed; production needs approval.', state: 'needs-you', meta: 'Waiting for you', counts: { tools: 9, files: 14 }, actions },
  { id: '2', title: 'Clean up CRM contacts', summary: 'Found 312 duplicates; wants to merge them.', state: 'needs-you', meta: 'Waiting for you', counts: { tools: 4 }, actions },
  { id: '3', title: 'Review PR #482', summary: 'Billing webhooks: reading the diff and the test run, writing review comments.', state: 'running', meta: '3m 41s', counts: { tools: 12, files: 21 } },
  { id: '4', title: 'Release notes v2.4', summary: 'Grouping 23 merged pull requests into features and fixes.', state: 'running', meta: '1m 19s', counts: { tools: 23, files: 5 } },
  { id: '5', title: 'Weekly metrics digest', summary: 'Pulled numbers from three dashboards and posted the summary.', state: 'done', meta: '4m 12s', counts: { tools: 3, files: 8 } },
]

function Demo() {
  const [view, setView] = useState<'board' | 'list'>('board')
  return <AgentInbox className="w-[52rem]" tasks={tasks} view={view} onViewChange={setView} />
}

export const styles = { Board: Demo, List: () => <AgentInbox className="w-[40rem]" tasks={tasks} view="list" /> }

Source: packages/ui/src/agent-inbox/agent-inbox.tsx

Catalog

Category
ai-agents
Priority
Pro
Primitive
composed
React Aria
GridList