Candor's principles
When an agent changes something real, the interface is where a person decides whether to trust it. These are the rules every Candor component keeps so that trust is earned, and where the kit enforces each one. To see four of them working beside what an agent UI typically shows, see Honest vs. typical.
01Model output is text, never markup
A model can be talked into writing a link, a script or a fake button. If the interface renders what it writes, whoever controls the prompt controls the page.
Adapters read model text as a small safe subset of markdown: paragraphs, lists, code, bold and italic. Links become plain text with the address beside them. Nothing a model writes is ever HTML.
In:MessageMessage contentSafe markdownAI SDKClaude Agent SDK
02Unknown stays unknown
A guessed duration, cost or count looks exactly like a measured one. People make decisions on numbers, so a number that wasn't measured shouldn't be shown as one.
Fields the service didn't report are left empty or say “not measured”. Costs an SDK estimates are labelled as estimates. A run receipt with no measured cost says so instead of showing $0.00. A run nothing has been heard from lately says when it was last heard, not that it's running.
In:Run receiptTool callUsage metersRun estimateSpend breakdownRun heartbeat
03A control that can't be used says why
A greyed-out button with no explanation sends people looking for help, or around the rule. Saying why turns a dead end into a next step.
Locked controls carry a reason, shown on hover and focus and read by screen readers: who can do it, what's missing, or what has to happen first.
04Nothing is pre-selected in a decision
A default in an approval nudges people to agree without reading. When an agent asks to change something real, the person should choose, not confirm.
Approve and reject, allow and deny start with neither chosen. Destructive choices never sit under a one-key shortcut, and the agent's own permission prompts can open on Deny.
05Approve the exact change
An approval given for one change shouldn't apply to another. If the change moves after someone looked at it, their approval no longer means what they meant.
Approval requests carry a hash of the change; a decision is tied to that hash, and a change that drifted since is rejected by the system. The blocks refuse self-approval and can require two people for production.
06Reasoning is believed, not verified
A model's account of why it did something is a claim, not evidence. Presenting it as fact gives it more weight than it has earned.
Reasoning is shown as the model's own account and marked as unchecked. Evidence is shown as evidence: sources, test results, the diff.
07The agent is always named, by the app
People need to know who did something, and a model shouldn't get to choose its own name or speak as the system.
Every agent message names its agent from the app's data, never from model output. System lines are the app's own strings.
08Say what can and can't be undone
Before something destructive, the question people need answered is “can I take this back?”. Hiding the answer in a confirmation they'll click through doesn't help.
Destructive actions say what they remove and whether it can be brought back, and the riskiest ones ask the person to type a name to confirm.
09Motion follows the outcome
A tick that appears before the clipboard answers, or a bar that fills before the work is done, teaches people that the interface's signals mean nothing. Motion is a claim about what happened, and a claim made early is a false one.
Motion reports a change that happened and never predicts or decorates one. A success mark is drawn after the result settles, a rail fills only to the step that finished, and a state that was already final when the page drew does not animate. data-motion sets none, subtle or expressive; the OS's reduced-motion setting wins over all three.
In:Copy fieldMessage actionsStep listTool callContext meterLockedPermission promptThread