Xzero UI
Pro library

Task breakdownPro

A goal input where AI breaks one sentence into a plan: tasks stream in with estimates, owners and dependencies, and a live timeline shows whether the deadline holds. Reorder, edit or regenerate any task, then send the plan to Linear or Jira with progress for each issue and links.

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

Drop <TaskBreakdown /> into a planning surface. With no props it plays a simulated plan. Pass generate(goal, signal) returning TaskDraft[] (id, title, estimate in working days, ownerId, dependsOn) and the block streams the rows in, works out the critical path, the ship date and the slack against deadline, and keeps them current as people edit. Pass createIssue(target, task, signal) returning { key, url } to create real Linear or Jira issues one by one in list order. regenerate rewrites a single task, owners supplies your team's portraits, and onTasksChange and onSent report edits and finished exports.

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/task-breakdown

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 { TaskBreakdown } from "@/components/xzero/blocks/task-breakdown/task-breakdown";

export function PlanFromGoal() {
  return (
    <TaskBreakdown
      deadline="2026-12-01"
      generate={async (goal, signal) => {
        const res = await fetch("/api/plan", { method: "POST", body: JSON.stringify({ goal }), signal });
        return res.json();
      }}
      createIssue={async (target, task, signal) => {
        const res = await fetch(`/api/${target}/issues`, { method: "POST", body: JSON.stringify(task), signal });
        return res.json(); // { key: "BIL-241", url: "https://linear.app/..." }
      }}
    />
  );
}

API reference

TaskBreakdown

A goal input that turns one sentence into a project plan. Press Break down and, after a short "Planning tasks" shimmer, tasks stream into reserved rows in fast chunks, each with an estimate in working days, an owner avatar and its dependencies ("After 2, 3"). A summary above the list counts tasks and total effort, and a timeline bar draws the critical path from the start date toward the deadline marker with "Ships Nov 17, 10d early" or a warning when the plan runs late; both update live as rows land and as tasks change. Rows can be edited in place (title and estimate), reordered by dragging the grip or with the arrow keys, and regenerated one at a time. A dependency placed below its task turns into a "Waits on 5" warning. Send to Linear or Send to Jira creates one issue per task with a spinner per row, then swaps each row's actions for its issue key link. With no props it plays a simulated plan for "Launch usage-based billing by Dec 1".

PropTypeDefaultDescription
defaultGoalstring"Launch usage-based billing by Dec 1"Goal shown in the input on first render.
defaultTasksTaskDraft[]–Tasks to open with. The block then starts ready instead of empty and does not auto start. A TaskDraft has id, title, estimate (working days, steps of 0.5), ownerId and dependsOn (task ids).
ownersTaskOwner[]demoOwnersPeople tasks can be assigned to: id, name and an optional avatar URL (initials otherwise).
generate(goal: string, signal: AbortSignal) => Promise<TaskDraft[]>–Breaks a goal into tasks. Rows stream in visually as soon as it resolves. Stop aborts the signal. Simulated with the sample plan when omitted.
regenerate(task: TaskDraft, context: { goal: string; tasks: TaskDraft[] }, signal: AbortSignal) => Promise<Partial<Omit<TaskDraft, "id">>>–Rewrites one task. Return the fields to replace; the id and, unless returned, dependencies are kept. Simulated when omitted.
createIssue(target: "linear" | "jira", task: TaskDraft, signal: AbortSignal) => Promise<{ key: string; url: string }>–Creates one issue, called once per task in list order. A rejection marks that row failed with a retry button. Simulated (BIL-241 and up, PAY-318 and up) when omitted.
targets("linear" | "jira")[]["linear", "jira"]Trackers offered in the footer. The first one is the primary button.
startDateDate | string"2026-10-27"First working day of the plan. Weekends are skipped.
deadlineDate | string"2026-12-01"Ship-by date, drawn as the marker on the timeline and used for the early or late label.
modelstring"Claude Sonnet 5.5"Model named in the footer next to the Claude mark.
autoStartbooleantrue without defaultTasksRun the breakdown once when the block scrolls into view.
onTasksChange(tasks: TaskDraft[]) => void–Called after every edit, reorder or regeneration.
onSent(target: "linear" | "jira", issues: Record<string, { key: string; url: string }>) => void–Called once every task has an issue, keyed by task id.
classNamestring–Class on the root card.

Keyboard interactions

KeysAction
EnterIn the goal input, breaks the goal down. While drafting the same button stops.
ArrowUp / ArrowDownOn a row's grip, moves the task up or down; focus stays on the grip.
EnterWhile editing a row, saves the title and estimate.
EscapeWhile editing a row, cancels the edit.
TabMoves through the goal, each row's grip, regenerate and edit buttons, issue links and the footer actions.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Guidance for AI tools

Blocks are complete, self-contained screens with sample data. Replace the sample data and connect the callbacks described above. 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