# kpis

One to eight figures side by side, each with a label, such as open tickets, agents working and median first reply.

Each of `tiles` reads one `source` of the screen and computes one figure: `count` (the rows), `sum` or `avg` of a
number `column`, `value` (the first row's cell) or `text` (the first row's cell, as written). `format` writes it:
`number`, `usd` ($6,140), `percent` (22%), `duration` (seconds as 4m 12s) or `bytes`. `caption` is a line under
the figure, `badge` a short word beside it, and `tone` (`neutral`, `ok`, `warn`, `bad`, `info`) says whether the
figure is good news. Every `column` but a `count` is required.

Category: data. Tier 1. Contract version 1.

## When to use

- The few figures a person checks first on a screen, such as the queue's open tickets and who needs a person.
- A month's totals, such as metered results and cost per closed ticket.
- Counts of rows a screen already reads, such as tickets waiting for approval.

## When to use another block

- One figure against a limit, such as the yearly cap used. Use [`progress`](/catalog/progress.md).
- A figure over time, such as tickets closed per hour. Use [`chart`](/catalog/chart.md).
- The rows behind the figures. Use [`grid`](/catalog/grid.md).

## Props

- `id` (name: a-z, 0-9 and -): The block's id: its Markdown anchor and its actions' route (`/act/<id>/<action>`). Default `<type>-<n>`, n counting blocks of this type depth-first from 1.
- `tiles` (list of 1–8: mapping, required): The tiles, in order.
  - `label` (text ≤ 60, required): The tile's label.
  - `source` (a source of the screen, required): The source the figure reads.
  - `figure` (one of count, sum, avg, value, text, default `count`): count: the rows; sum and avg: `column` over the rows; value and text: the first row's `column`.
  - `column` (column): The column the figure reads; required unless figure is count.
  - `format` (one of number, usd, percent, duration, bytes, default `number`): How the figure is written.
  - `caption` (text ≤ 120): A line under the figure.
  - `badge` (text ≤ 30): A short badge beside the figure.
  - `tone` (one of neutral, ok, warn, bad, info, default `neutral`): The tile's tone.

## Data

Reads each tile's `source`: its row count, or a column's sum or average, or the first row's cell.

Shape: any rows; a sum or avg column holds numbers.

## Actions

None: this block only shows.

## States

- **ready**: the source's rows, drawn
- **empty**: the source has no rows: an Empty part saying why and what comes next
- **error**: the source failed: "We couldn't load …" naming the block's rows, the source's sentence and Try again; the page still answers 200

## Examples

### The queue right now

```yaml
kpis:
  tiles:
    - { label: Open, source: summary, figure: value, column: open }
    - { label: Agents working, source: summary, figure: value, column: agents_working }
    - { label: Need a person, source: summary, figure: value, column: needs_person, tone: warn }
    - { label: Median first reply, source: summary, figure: value, column: first_reply_s, format: duration }
```

As an agent reads it:

```markdown
<a id="kpis-1"></a>

- Open: 214
- Agents working: 131
- Need a person: 27
- Median first reply: 4m 12s

```

### This month's cost

```yaml
kpis:
  tiles:
    - { label: Metered results, source: month, figure: value, column: metered_usd, format: usd, caption: so far this month }
    - { label: Cost per closed ticket, source: month, figure: value, column: cost_per_ticket_usd, format: usd, caption: all-in }
    - { label: Closed without a person, source: month, figure: value, column: no_person_pct, format: percent, tone: ok }
```

As an agent reads it:

```markdown
<a id="kpis-1"></a>

- Metered results: $6,140 (so far this month)
- Cost per closed ticket: $1.28 (all-in)
- Closed without a person: 61%

```

### Orders waiting for approval

```yaml
kpis:
  tiles:
    - { label: Waiting for approval, source: pending, badge: today }
    - { label: Value waiting, source: pending, figure: sum, column: amount_usd, format: usd, tone: info }
```

As an agent reads it:

```markdown
<a id="kpis-1"></a>

- Waiting for approval: 2 [today]
- Value waiting: $1,770

```

## Invalid

```yaml
kpis:
  tiles:
    - { label: Value waiting, source: pending, figure: sum, format: usd }
```

Answers: `kpis.tiles[0].column: missing; a sum figure reads a column`

## Composition

- Sits in: screen, card
- Pairs with: grid, chart, progress
- Three or four tiles read at a glance; eight is the most.
- One kpis block at the top of a screen, above the rows it sums up.
- Apple HIG: Lead with the information people need most, with short labels and clear figures.

## Telemetry

kpis.view

JSON Schema: [/catalog/kpis.schema.json](/catalog/kpis.schema.json)
