Plan Card

Plan mode's moment of trust: the agent proposes, you inspect and approve. The same card renders live execution afterwards — steps flip to done — and PlanCardCheckpoint is the settled timeline strip with a Restore key.

Proposed plan
Migrate billing webhooks to the new queue.
  1. Add a queue consumer for stripe events
  2. Backfill unprocessed webhooks from the log
  3. Cut the legacy endpoint over behind a flag
  4. Run the billing e2e suite
tsx
"use client"

import * as React from "react"

import {
  PlanCard,
  PlanCardStep,
  type PlanDecision,
} from "@/registry/seam/ui/plan-card"
import { Button } from "@/registry/seam/ui/button"

export default function PlanCardDemo() {
  const [decision, setDecision] = React.useState<PlanDecision | undefined>(
    undefined
  )

  return (
    <div className="flex flex-col items-start gap-3">
      <PlanCard
        description="Migrate billing webhooks to the new queue."
        decision={decision}
        onApprove={() => setDecision("approved")}
        onReject={() => setDecision("rejected")}
      >
        <PlanCardStep index={1}>
          Add a queue consumer for stripe events
        </PlanCardStep>
        <PlanCardStep index={2}>
          Backfill unprocessed webhooks from the log
        </PlanCardStep>
        <PlanCardStep index={3}>
          Cut the legacy endpoint over behind a flag
        </PlanCardStep>
        <PlanCardStep index={4}>Run the billing e2e suite</PlanCardStep>
      </PlanCard>
      {decision ? (
        <Button
          variant="ghost"
          size="sm"
          className="text-muted-foreground text-xs"
          onClick={() => setDecision(undefined)}
        >
          Reset demo
        </Button>
      ) : null}
    </div>
  )
}
bunx --bun @seamui/cli@latest add plan-card

Notes

  • The proposal is a raised key; steps are a semantic <ol> flat inside it; the checkpoint strip is debossed muted — settled history, not a demand. Deciding settles the card into a receipt, announced politely.
  • Controlled: onApprove() / onReject() out, decision in; step progress is your state via the done prop. Done steps swap their number for a check, mute, and announce as “(completed)”.
  • Pairs with tool for the steps' execution details and permission-card for approvals that arise mid-plan.

Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.