Agent cursor
ProA live document where Claude edits like a collaborator. Its labeled cursor comes out of its avatar, selects a paragraph and streams in a rewrite, adds a heading and fixes a typo, while a teammate's cursor reads along. Changes stay tinted until someone accepts or undoes them from a floating review bar.

Usage-based billing launch
On November 18 every Team workspace moves to usage-based billing: seats plus metered agent runs, invoiced monthly through Stripe.
Goals
So basically the main thing we are trying to do here is make it so customers can actually see what they are going to pay before the invoice shows up, because a lot of people were surprised by their bills last quarter and that turned into a lot of support tickets.
Week one goes to 5% of workpsaces behind the usage_billing flag. We widen to 50% once refund requests stay under 0.4% for seven days, then ship to everyone on December 2.
- Showing an AI writing assistant that edits a doc alongside people, with accept and undo.
- Landing or onboarding sections that demo a collaborative AI editor in motion.
- A product surface that streams structured edits from an agent and needs a human review step.
- Free form chat or Q&A: use a chat transcript component.
- A real rich text editor: wire your editor's own collaboration cursors; this card renders read-only blocks.
- Long documents with many sections: the card is built for a short excerpt of five to ten blocks.
Installation
Pro source and install commands unlock with a Pro plan.
import { AgentCursor, type AgentEdit, type DocBlock } from "@/components/arc/agent-cursor/agent-cursor"; const [doc, setDoc] = useState<DocBlock[]>(initialDoc); <AgentCursor blocks={doc} run={async signal => { const res = await fetch("/api/agent/edits", { method: "POST", body: JSON.stringify(doc), signal }); return (await res.json()) as AgentEdit[]; }} collaborator={{ name: "Emma Collins", avatar: "/media/people/emma-collins.jpg" }} onAccept={setDoc}/>AgentCursor
A document card where an AI agent edits live with a labeled cursor beside a human collaborator, then hands the changes over for review. With no props it plays a simulated run on a sample launch brief.
blocksDocBlock[]sample launch briefThe document as title, heading and paragraph blocks with stable ids. Compared by content, so an inline array is fine.metastring–A muted line under the title, such as the owner and a target date.editsAgentEdit[]sample editsEdits to play in order: rewrite (select a block and stream new text), insert (add a block after another) and fix (replace a word, flagged with a wavy underline first). Ignored when run is set.run(signal: AbortSignal) => Promise<AgentEdit[]>–Fetches edits from your agent. The signal aborts when someone presses Stop. A rejected promise shows the error with a Retry button.agent{ name: string; mark?: ReactNode; color?: string }Claude, #D97757The agent's name, 24 × 24 currentColor mark, and the color used for its cursor, selection and change tint.collaborator{ name: string; avatar?: string; color?: string } | nullEmma CollinsA human in the doc, drawn as a second cursor with their portrait and first name. Null hides it.autoPlaybooleantrueStarts a run as soon as the card is on screen. Off, the header shows an Ask button instead.loopbooleantrue for the sampleReplays the run: the collaborator accepts after a short pause (never while you hover or focus the card), then the doc resets.speednumber1Playback speed multiplier for cursor travel, streaming and pauses.onAccept(blocks: DocBlock[]) => void–Called with the edited document when someone accepts. Store it and pass it back as blocks.onUndo(blocks: DocBlock[]) => void–Called with the restored document when someone undoes the edits.onPhaseChange(phase: AgentCursorPhase) => void–Fires on idle, thinking, editing, review, accepted, reverted, stopped, empty and error.simulatedbooleantrue for the sampleAdds "Simulated, nothing was saved" to the screen reader status.classNamestring–Extra class on the card.- Tab
- Moves between Stop or Run again in the header, then Undo and Accept changes in the review bar.
- EnterorSpace
- Activates the focused button.
- A polite live region announces each step (reading, the current edit, edits ready, accepted, undone, errors), and adds "Simulated, nothing was saved" for simulated runs.
- Cursors, selections and the visual status line are decorative and hidden from assistive tech; the document stays real headings and paragraphs, marked aria-busy while the agent edits.
- Status never relies on color: every terminal state pairs an icon with a label, and pending changes are tinted and listed in the review bar with a count.
- Focus inside the card or a hovering pointer holds the looping demo in review, so nobody loses the bar mid reach.
- Cursors glide on a gentle quadratic arc with an ease-in-out curve, 280 to 600ms by distance, driven by motion values so nothing re-renders per frame.
- Selections fill line by line in step with the drag. Rewrites fade the old text out in 110ms, then stream 3 to 6 words every 34ms, each chunk fading in over 140ms with no blur or slide.
- Block heights follow measured content with a bounce-free spring (0.24s); inserted blocks grow from zero, then their text fades in.
- Status labels crossfade (100ms out, 160ms in). The review bar rises 8px and fades in 200ms.
- Reduced motion: cursors jump to each target, text appears whole, the loop and idle drift stop, and every end state stays.
- Playback pauses while the card is off screen.
- Fluid up to 680px wide; under 480px the doc padding tightens and the review bar drops "by Claude" to stay on one line.
- Cursor tags flip to the left of the arrow near the right edge, and resting cursors re-anchor when the card resizes.
- Works at 360px with no horizontal scroll; text wraps and the selection and cursor targets are measured from live line boxes.
- Cursor positions are motion values, so travel never re-renders React. Streaming re-renders one block per tick.
- Selection and target geometry come from Range.getClientRects on demand, not on every frame.
- Loops, idle drift and timers stop when the card is off screen or unmounted; Stop aborts the run's signal.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Pick this to show an AI agent editing a shared document in place, Notion or Google Docs style, with a review step. For a chat transcript use ai-chat; for a single text diff use a diff view.
- Feed real edits through run (async, abortable) or edits (static). Edits address blocks by id; fix edits need the exact word to replace inside the block text.
- Persist accepted text from onAccept and pass it back as blocks; the doc only resets to blocks when no run is using it.
- Set agent to another provider with its own mark and brand color; the cursor, selection and tint all follow agent.color.
The full library index for assistants is at /llms.txt.