# Usage ring

One usage against its limit as a large ring: the figure in the centre over "of $10", "{percent} used" under it (rounded down below 100 %, as ProgressRing does), and the level in UsageMeters' colours and lines (through `usageLevel`), said in words with an icon from 75 %, never by colour alone. Over the limit the ring is full and the words keep the measured figure ("$14 of $10", "140 % used"). Where the plan sets no limit there is no ring, only the figure and "No limit set".

Usage that's done but not metered yet (`pending`) is a striped arc after what's used, said in words, and how far a run may still go past the limit (`mayExceedBy`) is said under the ring, as UsageMeters has them: your figures, never the ring's.

The pace is the usage's `estimate`, your own figure: the kit computes none. It is drawn apart from the measured arc, as a thin dashed arc on its own inner track, and said under the ring with its label ("Estimate", or `estimateLabel`) and its basis in your words (`estimateBasis`: "at this month's daily average"), never on hover only. With no basis given, the words say none was given.

A figure that isn't known yet (`unknown`) draws a dashed track and "Not known yet", never an empty ring that reads as zero. `paused` is your statement that work has stopped (true, or your reason), never inferred from what's used.

The arc runs clockwise from 12 o'clock in every language, as a dial does. In forced colours it is drawn in `Highlight` on a `CanvasText` track.

- Registry name: `usage-ring` (`@candor/usage-ring`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/usage-ring

## Install

```bash
npx candor-ui add usage-ring
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/usage-ring`.
It brings in: bidi, locale, motion, ops, relative-time, tokens, usage-level, utils.
npm packages: lucide-react@^1.67.0.

## Example

```tsx
"use client"

import { UsageRing } from "@/components/candor/usage-ring"

export default function Example() {
  return (
    <div className="grid w-full gap-8 sm:grid-cols-3">
      {/* estimate: your own figure, drawn as a dashed inner arc and said with its basis. The kit computes no pace. */}
      <UsageRing
        usage={{ label: "Agent spend this month", used: 6.2, limit: 10, unit: "USD", usedText: "$6.20", limitText: "$10", estimate: 8.9, estimateText: "about $8.90" }}
        estimateBasis="at this month's daily average"
      />
      {/* pending: done but not metered yet; mayExceedBy: your provider's own figure. */}
      <UsageRing
        usage={{ label: "Agent spend today", used: 9.1, limit: 10, unit: "USD", usedText: "$9.10", limitText: "$10", pending: 0.6, pendingText: "about $0.60", mayExceedBy: 2, mayExceedByText: "$2" }}
        paused="Agents stop at the limit"
      />
      {/* No limit: the figure alone, no ring. */}
      <UsageRing usage={{ label: "Agent runs this week", used: 412, limit: null, unit: "runs" }} />
    </div>
  )
}
```

## <UsageRing>

Props:

- `usage: Usage`: What's used, the limit (null when there is none), the unit, and your `estimate`, `pending` and `mayExceedBy` figures.
- `estimateBasis?: string | undefined`: What the usage's `estimate` rests on, in your words that finish "Estimate: $8.20 …": "at this month's daily average". Shown under the ring. Left out, the words say no basis was given.
- `unknown?: boolean | undefined`: The figure isn't known yet (the provider hasn't reported): a dashed track and "Not known yet", never zero.
- `paused?: boolean | string | undefined`: The app's own statement that work is paused (by the limit, or by a person): true, or the reason in your words. Drawn with an icon under the ring. Never inferred from what's used.
- `className?: string | undefined`

## Strings (`usageRing`)

The fixed words, English by default. Override any of them under `usageRing` in `<LocaleProvider strings={{ usageRing: { … } }}>`; the table is exported as `usageRingStrings`.

- `usedOfLimit`: {used} of {limit}
- `ofLimit`: of {limit}
- `percentUsed`: {percent} used
- `amount`: {value} {unit}
- `noLimit`: No limit set
- `notKnown`: Not known yet
- `warning`: Nearing the limit
- `danger`: Close to the limit
- `atLimit`: At the limit
- `overLimit`: Over the limit
- `estimate`: Estimate
- `estimateValue`: {label}: {value} {basis}
- `estimateNoBasis`: {label}: {value}; no basis given
- `pending`: {value} not yet metered
- `mayExceed`: May go over the limit by up to {value}.
- `withPending`: {used}, {pending}
- `resets`: Resets {time}.
- `paused`: Paused
- `pausedBecause`: Paused: {reason}

## Types from other items

The props above take these. Each is defined by another item; import it from the path shown.

### Usage

Import: `import type { Usage } from "@/lib/candor/ops"` (item `ops`, https://candor.themethodic.com/docs/ops.md)

```ts
{
  label: string;
  used: number;
  /** null when there's no limit (the plan sets none). */
  limit: number | null;
  unit: string;
  resetsAt?: string | undefined;
  note?: string | undefined;
  /**
   * Your own estimate of where it will end, in the same unit (a quote, a forecast), marked on the bar. It is shown as
   * given and labelled as an estimate; nothing is extrapolated.
   */
  estimate?: number | undefined;
  /** Words for the estimate marker ("My guess"); defaults to the `usageMeters.estimate` string. */
  estimateLabel?: string | undefined;
  /**
   * The figures as your server wrote them, shown as they are instead of Candor's number formatting (with the unit
   * left to you): `used` ("about $4"), `limit` ("$10") and `estimate`. The numbers still place the bar and markers.
   */
  usedText?: string | undefined;
  limitText?: string | undefined;
  estimateText?: string | undefined;
  /**
   * Work already done that your provider hasn't metered yet, in the same unit: it will count, but isn't in `used`.
   * Drawn after the used part of the bar, striped, and said in words ("about $1 not yet metered").
   */
  pending?: number | undefined;
  /** `pending` as your server wrote it ("about $1"), shown as written. */
  pendingText?: string | undefined;
  /**
   * How far past the limit this may still go, from your own figure (a provider that checks the limit between steps, a
   * run already under way), in the same unit. Said under the meter; the meter never works it out.
   */
  mayExceedBy?: number | undefined;
  /** `mayExceedBy` as your server wrote it, shown as written. */
  mayExceedByText?: string | undefined;
}
```

## Motion

- **fill** (fill): The used arc (and the pending one after it) moves from the old measured amount to the new one when it changes while the ring is on screen. The first amount is drawn in place, never swept from empty, and a limit or figure that isn't known shows no arc to move.

Set with `--cd-motion-usage-ring-<moment>-*` in your brand file; the families are in the design reference.

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
