Checkpoint list

Pro

Restore points in a run, one per turn, with what each one holds and where the person is now. Each checkpoint says what happened, when, who made it, and what it captured (files, conversation or both, with counts when the app knows them), and offers a Restore that the app handles, usually by opening RestoreDialog. A checkpoint that can't be restored stays listed with its Restore locked and the reason beside it. Nothing is selected for the person, and a note says what checkpoints don't capture.

Markdown

Preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/checkpoint-list

Brings in: badge, button, locale, locked, relative-time, surface, utils · npm: lucide-react@^1.67.0

Usage

TSX · The example above
"use client"

import type { Checkpoint } from "@/components/checkpoint-list"
import { CheckpointList } from "@/components/checkpoint-list"

const minutesAgo = (m: number) => new Date(Date.now() - m * 60_000)

const checkpoints: Checkpoint[] = [
  { id: "cp-5", label: "Wired the rate limiter into the API routes", createdAt: minutesAgo(2), captured: "both", fileCount: 4, messageCount: 18, madeBy: { kind: "agent", name: "Build agent" } },
  { id: "cp-4", label: "Added tests for burst traffic", createdAt: minutesAgo(9), captured: "both", fileCount: 2, messageCount: 14, madeBy: { kind: "agent", name: "Build agent" } },
  { id: "cp-3", label: "Before renaming the config keys", createdAt: minutesAgo(21), captured: "files", fileCount: 31, madeBy: { kind: "person", name: "Priya Shah" } },
  { id: "cp-2", label: "Added the token-bucket limiter", createdAt: minutesAgo(34), captured: "both", messageCount: 6, madeBy: { kind: "agent", name: "Build agent" } },
  {
    id: "cp-1",
    label: "Session start",
    createdAt: minutesAgo(60 * 26),
    captured: "both",
    unavailable: "Its file snapshot was removed after 24 hours.",
  },
]

export default function Example() {
  return <CheckpointList className="max-w-xl" checkpoints={checkpoints} currentId="cp-5" onRestore={() => {}} />
}

<CheckpointList>

PropTypeDefaultDescription
checkpointsrequiredCheckpoint[]—The checkpoints in the order to show them; newest first is usual.
currentIdstring | undefined—The checkpoint the work is at now. It's marked, and has no Restore.
onRestore((id: string) => void) | undefined—Called with a checkpoint's id when the person picks Restore. Without it, there are no Restore buttons.
notestring | null | undefined—What checkpoints don't capture, in the app's words. Defaults to shell commands and changes outside the agent; null hides it.
classNamestring | undefined—Extra classes for the outer element.

Strings

The fixed words, in English by default. Change any of them under checkpointList in <LocaleProvider strings={{ … }}>; the table is exported as checkpointListStrings.

KeyEnglish
titleCheckpoints
count{ one: "{count} checkpoint", other: "{count} checkpoints" }
emptyNo checkpoints yet.
currentYou are here
restoreRestore
restoreToRestore to “{label}”
capturedHolds
filesfiles
conversationconversation
bothfiles and conversation
fileCount{ one: "{count} file", other: "{count} files" }
messageCount{ one: "{count} message", other: "{count} messages" }
byAgentBy {name} (agent)
byPersonBy {name}
noteCheckpoints hold the agent’s own file edits and the conversation. Shell commands it ran and changes made outside it aren’t captured, so a restore doesn’t undo them.

Types

CheckpointCapture
What a checkpoint holds: the files, the conversation, or both.
"files" | "conversation" | "both"
Checkpoint
One restore point, usually one per turn.
{ id: string /** What happened at this point, in plain words: "Added the rate limiter". */ label: string /** When the checkpoint was made. */ createdAt: Date | string /** What it holds. A restore can only put back what was captured. */ captured: CheckpointCapture /** How many files it holds, when the app knows. Left out, no count is shown. */ fileCount?: number | undefined /** How many messages of