Skip to content

Voice and tone

How Oration sounds: professional, clear and friendly, and how the tone shifts from a greeting to an error.

Oration's voice#

One voice across the CRM, the Agents Platform, the Contact Center and Ticketing: professional, clear, friendly, operational and specific. The voice stays fixed; the tone moves with the moment.

  1. Professional

    Written for people doing their jobs, with money and customers on the line. Steady, never cute.

    Sounds like “Payment run approved.”

    Not: “Boom! Payments are on their way!”

  2. Clear

    Plain words a tired reader gets on the first pass. One idea per sentence, the important word first.

    Sounds like “Couldn't send the remittance. Check the supplier's email address.”

    Not: “Remittance dispatch encountered an unexpected delivery exception.”

  3. Friendly

    Warm through respect and help, not exclamation points. We greet people, thank them when they did us a favor, and never scold.

    Sounds like “Good morning, Maya.”

    Not: “Hey superstar, ready to crush it today?”

  4. Operational

    Copy is for doing the work. Say what happened, what it means and what to do next, in the order the reader needs it.

    Sounds like “3 invoices failed matching. Review them before Thursday's run.”

    Not: “Unlock the power of intelligent matching across your AP workflow.”

  5. Specific

    Names, amounts, dates and counts beat categories. Specific copy is shorter, because it doesn't need to explain itself.

    Sounds like “Halcyon Packaging's W-9 expired on September 1.”

    Not: “Some supplier documents may need attention.”

The voice comes from PRODUCT.md: professional, clear, friendly operational copy, such as dated summaries and direct task labels, and never hype on the surfaces where people work. It is the voice of a colleague who knows the books: they tell you what changed, show you the figure and leave the decision with you.

Principles#

Six habits that turn the voice into copy. Each one is shown as the draft that usually comes first and the line that ships.

1Lead with the outcome

Put what happened, or what the reader can do, first. Detail follows for those who want it.

Before: We have successfully completed processing your payment run request.

After: Payment run approved.

2Name the thing

Say which record, which person, which amount. A pronoun or a category makes the reader go and look.

Before: Item updated.

After: Northwind Freight's remittance email updated.

3Say what happens next

When an action starts something, say when it finishes or how the reader will know.

Before: Your import has been queued.

After: Importing 248 suppliers. You'll get a notification when it's done.

4Use the reader's words

Write in the reader's domain, not the system's. Suppliers, invoices and payment runs, not entities, objects and jobs.

Before: Entity sync failed for 3 objects of type vendor.

After: Couldn't update 3 suppliers.

5Stay calm as the stakes rise

The bigger the consequence, the plainer the words. Never raise the volume to make a point.

Before: WARNING!!! This action is PERMANENT and CANNOT be undone!

After: This can't be undone. Paid invoices stay in the audit log.

6Be friendly, not familiar

Courtesy without performance. No slang, no emoji, no in-jokes that don't translate.

Before: Hey there! Ready to rock your pipeline today?

After: Good morning, Maya. 4 decisions are waiting.

Tone by moment#

Tone rises and falls with the stakes. Light where nothing is at risk, plain and serious where money, data or a customer is.

Eight moments, live

Each moment rendered with the component that carries it. Step through them and try the actions.

Good morning, Maya

Monday, September 28. 4 decisions waiting and 3 meetings on your calendar.

import { ApprovalCard } from "@oration/canon/components/ai/approval-card";import { Button } from "@oration/canon/components/button";import { ConfirmDialog } from "@oration/canon/components/confirm-dialog";import { EmptyState, ErrorState } from "@oration/canon/components/data-state";import { Meter } from "@oration/canon/components/meter";import { SideTabs, sideTabId } from "@oration/canon/components/side-tabs";import { toast } from "@oration/canon/components/toast";import { CircleCheckIcon, FileTextIcon, GaugeIcon } from "lucide-react";import * as React from "react";export function ToneByMoment() {    const panelId = React.useId();    const [moment, setMoment] = React.useState("greeting");    const [confirmOpen, setConfirmOpen] = React.useState(false);    const moments = [        { id: "greeting", label: "Home greeting", meta: "Warm, brief" },        { id: "empty", label: "Empty state", meta: "Helpful" },        { id: "success", label: "Success", meta: "Quiet" },        { id: "error", label: "Error", meta: "Calm, plain" },        { id: "destructive", label: "Destructive", meta: "Serious" },        { id: "proposal", label: "AI proposal", meta: "Evidence first" },        { id: "limits", label: "Limits and billing", meta: "Neutral, exact" },        { id: "onboarding", label: "Onboarding", meta: "Encouraging" },    ];    return (        <div className="grid w-full max-w-3xl gap-4 text-left md:grid-cols-[12rem_minmax(0,1fr)]">            <SideTabs                label="Moments"                items={moments}                value={moment}                onValueChange={setMoment}                panelId={panelId}                orientation="vertical"            />            <div                id={panelId}                role="tabpanel"                aria-labelledby={sideTabId(moment)}                className="flex min-h-72 min-w-0 items-center justify-center rounded-xl bg-card p-5 shadow-border"            >                {moment === "greeting" ? (                    <div className="w-full">                        <p className="text-2xl font-semibold tracking-[-0.02em] text-foreground">                            Good morning, Maya                        </p>                        <p className="mt-1 text-sm text-muted-foreground">                            Monday, September 28. 4 decisions waiting and 3                            meetings on your calendar.                        </p>                    </div>                ) : null}                {moment === "empty" ? (                    <EmptyState                        illustration="done"                        title="No invoices on hold"                        description="Invoices that fail matching wait here for someone to approve or reject the match."                        action={                            <Button                                variant="outline"                                onClick={() =>                                    toast.add({                                        title: "Matching rules opened",                                    })                                }                            >                                View matching rules                            </Button>                        }                    />                ) : null}                {moment === "success" ? (                    <div className="flex w-full max-w-sm flex-col items-center gap-4">                        <div className="flex w-full items-start gap-3 rounded-[10px] bg-muted/70 p-3">                            <CircleCheckIcon                                aria-hidden="true"                                className="mt-0.5 size-4 shrink-0 text-success"                            />                            <div className="flex flex-col gap-0.5">                                <p className="text-13 font-medium text-foreground">                                    Payment run approved                                </p>                                <p className="text-13 text-muted-foreground">                                    14 invoices for $86,412.50 go out Thursday,                                    October 1.                                </p>                            </div>                        </div>                        <Button                            variant="outline"                            onClick={() =>                                toast.add({                                    type: "success",                                    title: "Payment run approved",                                    description:                                        "14 invoices for $86,412.50 go out Thursday, October 1.",                                })                            }                        >                            Show the toast                        </Button>                    </div>                ) : null}                {moment === "error" ? (                    <ErrorState                        title="Couldn't load payment runs"                        description="The request timed out. Nothing was changed. Try again in a moment."                        onRetry={() =>                            toast.add({ title: "Loading payment runs again" })                        }                    />                ) : null}                {moment === "destructive" ? (                    <div className="flex flex-col items-center gap-3 text-center">                        <p className="max-w-xs text-13 text-muted-foreground">                            The dialog names the supplier, says what goes and                            what stays, and repeats the action on its button.                        </p>                        <Button                            variant="destructive"                            onClick={() => setConfirmOpen(true)}                        >                            Delete supplier                        </Button>                        <ConfirmDialog                            open={confirmOpen}                            onOpenChange={setConfirmOpen}                            destructive                            title="Delete Halcyon Packaging?"                            description="This removes the supplier and takes its 3 open invoices out of upcoming payment runs. Paid invoices and remittance history stay in the audit log."                            confirmLabel="Delete supplier"                            onConfirm={() =>                                toast.add({                                    title: "Halcyon Packaging deleted",                                    description:                                        "3 open invoices left the October 1 run.",                                })                            }                        />                    </div>                ) : null}                {moment === "proposal" ? (                    <ApprovalCard                        className="w-full"                        icon={<FileTextIcon />}                        title="Hold INV-20431 until Halcyon sends a W-9"                        description="From Nora's call with Halcyon at 9:40 AM. The W-9 on file expired on September 1."                        fields={[                            {                                label: "Invoice status",                                before: "Scheduled for Oct 1",                                after: "On hold",                            },                            {                                label: "Supplier task",                                after: "Upload a current W-9",                            },                        ]}                        footnote="Updates 1 invoice and emails Halcyon"                        approveLabel="Hold invoice"                        onApprove={() =>                            toast.add({                                type: "success",                                title: "INV-20431 on hold",                                description:                                    "Halcyon was asked for a current W-9.",                            })                        }                        onSkip={() => toast.add({ title: "Proposal skipped" })}                    />                ) : null}                {moment === "limits" ? (                    <div className="flex w-full max-w-sm flex-col gap-3">                        <div className="flex items-center gap-2 text-sm font-medium text-foreground">                            <GaugeIcon                                aria-hidden="true"                                className="size-4 text-muted-foreground"                            />                            9,200 of 10,000 credits used                        </div>                        <Meter value={9200} max={10000} label="Credits used" />                        <p className="text-13 text-muted-foreground">                            Enrichment pauses at 10,000 credits. Credits reset                            on October 1, or you can add more now.                        </p>                        <div>                            <Button                                variant="outline"                                onClick={() =>                                    toast.add({                                        title: "Billing opened",                                        description:                                            "Add credits from the usage tab.",                                    })                                }                            >                                Add credits                            </Button>                        </div>                    </div>                ) : null}                {moment === "onboarding" ? (                    <div className="flex w-full max-w-sm flex-col gap-3">                        <p className="text-xs text-muted-foreground tabular-nums">                            2 of 6 steps done                        </p>                        <p className="text-sm font-semibold text-foreground">                            Build your first voice agent                        </p>                        <p className="text-13 text-muted-foreground">                            Give it a voice and a procedure to follow, then call                            it from your browser before it takes a supplier                            call.                        </p>                        <div>                            <Button                                onClick={() =>                                    toast.add({                                        title: "New agent",                                        description:                                            "Name it and pick a voice to start.",                                    })                                }                            >                                Build an agent                            </Button>                        </div>                    </div>                ) : null}            </div>        </div>    );}
Tone and example copy by moment
MomentToneShipsNever
Home greetingWarm, brief, factualGood morning, Maya with “Monday, September 28. 4 decisions waiting and 3 meetings on your calendar.”Welcome back, superstar. Let's crush Monday!
Empty statesHelpful, pointing forwardNo invoices on hold with “Invoices that fail matching wait here for someone to approve or reject the match.” and View matching rulesNothing here yet! It's lonely in here.
SuccessQuiet, past tensePayment run approved with “14 invoices for $86,412.50 go out Thursday, October 1.”Woohoo! You did it!
ErrorsCalm, plain, no blameCouldn't load payment runs with “The request timed out. Nothing was changed. Try again in a moment.” and RetryOops! Something went wrong.
Destructive confirmationsSerious, explicitDelete Halcyon Packaging? with what goes, what stays, and Delete supplierAre you sure? Yes or No.
AI proposalsEvidence first; the person decidesHold INV-20431 until Halcyon sends a W-9 with “From Nora's call with Halcyon at 9:40 AM. The W-9 on file expired on September 1.” and Hold invoiceOur AI magically spotted a problem and fixed it for you!
Limits and billingNeutral, exact, no pressure9,200 of 10,000 credits used with “Enrichment pauses at 10,000 credits. Credits reset on October 1, or you can add more now.”You're almost out! Upgrade now to avoid disruption.
OnboardingEncouraging, concreteBuild your first voice agent with “Give it a voice and a procedure to follow, then call it from your browser.” and Build an agentLet's get you set up in no time!

The tone dial in one line

The closer the copy sits to money, data loss, security or a customer, the less personality it carries. Greetings and empty states can be warm; destructive confirmations and billing are plain.

How AI speaks#

Agents propose, people decide. AI copy shows its evidence, states the change it wants, and leaves the decision with a person. It never claims a mind or a mood.

A proposal written well

The title is the action in plain words. The description is the evidence: where it came from and why. The fields show the change, and the button repeats the verb.

Move Orchard Street's payment to October 5

Orchard Street's AP lead asked on Nora's 10:15 AM call. Their bank account changes on October 2, so the October 1 run would pay the account that is closing.

Payment date
Before: Oct 1After: Oct 5
Early-pay discount
Before: 2% ($146.10)After: None, past the 10-day window
Updates 1 payment and notifies Orchard Street
import { ApprovalCard } from "@oration/canon/components/ai/approval-card";import { toast } from "@oration/canon/components/toast";import { FileTextIcon } from "lucide-react";export function ProposalCopy() {    return (        <ApprovalCard            className="w-full max-w-lg text-left"            icon={<FileTextIcon />}            title="Move Orchard Street's payment to October 5"            description="Orchard Street's AP lead asked on Nora's 10:15 AM call. Their bank account changes on October 2, so the October 1 run would pay the account that is closing."            fields={[                { label: "Payment date", before: "Oct 1", after: "Oct 5" },                {                    label: "Early-pay discount",                    before: "2% ($146.10)",                    after: "None, past the 10-day window",                },            ]}            footnote="Updates 1 payment and notifies Orchard Street"            approveLabel="Move payment"            onApprove={() =>                toast.add({                    type: "success",                    title: "Payment moved to October 5",                    description: "Orchard Street was notified.",                })            }            onEdit={() => toast.add({ title: "Editing the proposal" })}            onSkip={() => toast.add({ title: "Proposal skipped" })}        />    );}

Agents propose, people decide

An agent's work that changes a record, sends a message or spends money arrives as a proposal with Approve, Edit and Skip, or the action's own verb. The copy never implies the change already happened.

Evidence before opinion

Say where a suggestion came from (a call, an email, a record) and what it rests on. State confidence as a label such as High confidence, never as certainty.

Software, not a colleague

Agents are named products: Nora, the agent, it. They find, draft, propose and transfer. They don't feel, want, love or get excited.

The Copilot reports, then offers

The Copilot answers with the finding first and offers the next step as a draft or a proposal: “Here's a reply that explains it.” It keeps “I” for its own actions and never apologizes for existing.
Verbs for AI work
WriteInstead ofWhy
Nora proposesNora wants to, Nora would love toA proposal is a request, not a wish
Drafted, found, matched, summarizedThought about, figured out, realizedDescribe the output, not an inner life
Transferred the call to PriyaDecided to hand you offSay what happened and to whom
Couldn't find a W-9 for HalcyonNora is confusedName what's missing
Draft reply, Summarize callAI magic, Smart replyThe button names the action

Hold INV-20431 until Halcyon sends a W-9

From Nora's call at 9:40 AM. The W-9 on file expired on September 1.

Do. Name the action and the evidence, and let the person decide.

Your AI teammate is on it!

Nora noticed something fishy and magically took care of Halcyon's invoice for you.

Don't. Speak as a delighted teammate and imply the change is done.

Where to put AI in the interface is covered in AI assistance. The card itself is Approval card.

One voice across four apps#

Each app's readers bring their own vocabulary and pace. The voice holds; the register adjusts.

Register by app
AppReaderRegisterSounds like
CRMRevenue team, MayaPipeline language, amounts and dates up front“Halcyon has been quiet for 17 days. $148,000 closes October 16.”
Agents PlatformConversation designers and AI opsPrecise, technical terms explained in an Info tip“End-to-end latency is 820 ms at p95, above the 800 ms target.”
Contact CenterSupport agents under loadShort and scannable; drafts to customers are warmer“Caller verified. Payment PMT-58213 went out September 25.”
TicketingSupport team triagingTerse, past tense, Linear-like“Assigned to Wen. Moved to In progress.”
  • Copy that Cedarline sends to its own customers, such as a drafted supplier reply, is written in Cedarline's voice and signed by a person. Oration's voice is for the interface around it.
  • Use the same word for the same thing in every app. A ticket is a ticket in the Contact Center too. See the glossary.

What we never say#

Words and habits that break the voice, why they do, and what to write instead.

Phrases Oration never uses
NeverWhyWrite instead
Oops, whoops, uh ohTurns a failure into a joke the reader didn't ask for.Couldn't save the sequence. Try again.
Something went wrong (alone)Says nothing about what failed or what to do.Couldn't load invoices. Check your connection and try again.
Invalid, illegal, error 422Blames the reader in system language.Enter an amount greater than $0.00.
Are you sure?Asks for courage instead of naming the consequence.Delete Halcyon Packaging?
SuccessfullyEvery completed action succeeded; the word adds nothing.Supplier added.
Simply, just, easy, quickMakes anyone who finds it hard feel slow.Upload a CSV of suppliers.
Seamless, revolutionary, supercharge, unlock, game-changingMarketing heat on an operating surface.Say what it does: Matches invoices to purchase orders.
AI-powered, magic, smart (as adjectives)Labels the technology instead of the action.Draft reply, Summarize call
Your AI teammate, she, heGives software a personhood it doesn't have.Nora, the agent, it
Click here, learn more (alone)Means nothing out of context or to a screen reader.Read the billing docs
Act now, don't miss outManufactured urgency.Credits reset on October 1.
We're sorry for any inconvenienceRitual apology instead of help.Fix it, or say how: Try again in a few minutes.
The userTalks about the reader instead of to them.You, or the role: the account owner
Exclamation points and emojiRaise the volume and don't translate. None in the UI.A period.

Claims we never make

Interface copy never asserts anything about Oration that isn't confirmed: no customer names, testimonials, revenue figures or compliance claims. The trust row on log in and sign up is the only place compliance programs appear. See Brand identity.