# Optimistic UI in p2 Every action whose effect the user waits to see shows that effect at once: the switch flips, the row is renamed, the message is in the transcript. This page is the pattern p2's plugins follow, on the web and in the terminal, and the reference for plugin authors. ## Why it works without flicker Two rules make an optimistic value safe to drop the moment its call settles: 1. **A method that should feel instant awaits its own effects** and keeps them on the host that answers (Chord's guide; decision "App authoring rules confirmed by the p2 audit"). `Sessions.rename` commits the catalog before it returns; `ChatMode.set` returns once the followed Durable document changed. 2. **A call's answer follows its state** (Chord decision of 2026-11-05): before a host sends a `result`, it sends the page the `state` it committed. When the call resolves on the page, the new value is already there. So the page shows a guess while the call is in flight and simply forgets it when the call settles: on success the real value has replaced it in the same frame; on failure the real value is the old one, so the guess rolls back by itself, and the error is shown. Nothing on the page reconciles a guess with the server's value, compares ids or waits for state after an answer. A method that returns before its effect (a background job, a native that reports later) breaks rule 1: its guess would vanish before the real value arrives. Such work shows a **pending state** instead (below), never a guess of its outcome. ## Web: `useOptimisticCall` `useOptimisticCall(value, apply, onError)` (`src/runtime/web.tsx`, from `@p2/app/v1/web`) is React's `useOptimistic` plus a transition: it returns `[shown, run, pending]`. ```tsx // plugins/chat-mode/web.tsx: the chat mode chip const { fail } = useComposerState(); // the app's toast const [{ enabled, name }, guess] = useOptimisticCall>( { enabled: useReadable(mode?.enabled) ?? false, name: useReadable(mode?.name) ?? DEFAULT_AGENT_NAME }, (shown, change) => ({ ...shown, ...change }), fail, ); // ...