# Overview

> Read your Reserved Instance, Savings Plan and Committed Use Discount position from the terminal: coverage, utilization, what expires, and what to buy next.

Source: https://docs.levelfour.ai/cli/commands/commitments


`l4 commitments` reads what your organization has already committed to, and what that commitment is
earning. It answers the questions the Commitments page answers, plus one it cannot: whether a term
is about to lapse, as an exit code a pipeline can act on.

`cmt` is an alias, so `l4 cmt list` and `l4 commitments list` are the same command.

Every subcommand is read-only. Nothing here buys, cancels or exchanges a commitment.

## Subcommands

| Command                                          | Purpose                                                      | Scope  |
| ------------------------------------------------ | ------------------------------------------------------------ | ------ |
| [`summary`](#summary)                            | Coverage, utilization and what the commitments are earning   | `read` |
| [`list`](#list)                                  | Every commitment held, soonest to expire first               | `read` |
| [`expiring`](/cli/commands/commitments/expiring) | What lapses soon, with an exit code for CI                   | `read` |
| [`view`](#view)                                  | Everything known about one commitment                        | `read` |
| [`renewal`](/cli/commands/commitments/renewal)   | What to repurchase when a term ends, and when to buy         | `read` |
| [`utilization`](#utilization)                    | How much of what was bought is being used                    | `read` |
| [`coverage`](/cli/commands/commitments/coverage) | How much of the eligible bill is covered, weighted           | `read` |
| [`plan`](#plan)                                  | The uncovered on-demand base, and what buying would cover it | `read` |
| [`contracts`](#contracts)                        | Marketplace floors that bill like a commitment               | `read` |

[`l4 export commitments`](/cli/commands/export#commitments) writes the same ledger as CSV or JSON.

## Which providers answer

AWS, Google Cloud and Azure all report. They do not report the same things, because the three clouds
expose different data.

| Command       | AWS  | Google Cloud                              | Azure                                             |
| ------------- | ---- | ----------------------------------------- | ------------------------------------------------- |
| `summary`     | full | coverage and utilization, no savings rate | coverage, utilization and expiry, no savings rate |
| `list`        | full | no expiry                                 | full                                              |
| `view`        | full | no term or expiry                         | full                                              |
| `coverage`    | full | a rate, but no covered spend              | one row per instrument, no per-service rows       |
| `export`      | full | no expiry                                 | full                                              |
| `expiring`    | full | not measured                              | full                                              |
| `renewal`     | full | not measured                              | sized from Azure's utilization                    |
| `utilization` | full | one entry, resource-based discounts only  | full                                              |
| `plan`        | full | not measured                              | Azure's own recommendations, priced on your bill  |
| `contracts`   | full | none collected                            | none collected                                    |

Azure sells the same two instruments as AWS, and the tables name them as Azure does: **Reservation**
and **Savings plan**. `--kind ri` and `--kind sp` select them.

`contracts` lists the whole organization's floors, whichever provider the command resolves, so
`--provider` only picks the page `--web` opens. DigitalOcean's reserved products appear there too,
because they bill as a contract: what they charge is the floor, and the rest of the bill is the
metered leg.

Google Cloud has no public on-demand equivalent to divide by, so there is no effective savings rate
to compute. Committed Use Discount term and expiry come from an export that Google ships separately,
and until it is enabled a Committed Use Discount has no end date on any surface.

Where a command cannot answer for the resolved provider it says so in one line and exits `0`:

```text
$ l4 commitments expiring --provider gcp
Commitment expiry is not measured for Google Cloud: the commitment lifecycle export is not enabled. Nothing checked.
```

It does not print an empty table. An empty table reads as "you hold none of these", which is a
different and wrong claim.

## `not measured` is not zero

Where a figure was never measured, these commands print `not measured` rather than `0`. The
distinction is load-bearing in five places:

* **A Savings Plan has no coverage.** Cost Explorer cannot filter coverage by plan type, so what one
  plan covers is unanswerable. The column reads `not measured`. A `0.0%` there would claim the plan
  covers none of your eligible usage.
* **Google Cloud has no savings rate**, for the reason above. `summary` prints `not measured`, never
  a rate derived from coverage.
* **Google Cloud's expiring count is unmeasurable**, not zero. A `0` would read as reassurance.
* **An Azure commitment's utilization can be unmeasured**, early in a month before Azure reports it.
  `list`, `view` and `summary` print `not measured`, and `export` leaves the cell empty. A `0.0%`
  would read as a commitment nobody used.
* **Totals come from the API**, never from summing a column. The monthly commitment amount is not
  populated on every term, so a client-side total would quietly understate the portfolio.

## Picking a provider

Every command reports on one provider. Without `--provider`, the CLI resolves the first provider it
can answer commitments for rather than the first one connected, so a Google Cloud organization with
another provider connected first still lands on its own data. A named `--provider` is always
honoured, whatever it is, because asking about one provider deserves an answer about that provider
rather than a silent redirect.

## summary

```bash
l4 commitments summary [flags]
```

Coverage, the commitment count, how many expire soon, and on AWS the effective savings rate split
into the part a negotiated agreement earns and the part commitments earn. Then one row per service,
with each instrument measured on its own.

The headline coverage figure is the same spend-weighted one
[`l4 commitments coverage`](/cli/commands/commitments/coverage) prints, from the same source, so the
two commands cannot report different coverage for one estate.

### Flags

| Flag                 | Description                                                          |
| -------------------- | -------------------------------------------------------------------- |
| `--provider <id>`    | `aws`, `gcp` or `azure` (resolved if omitted)                        |
| `--period <YYYY-MM>` | Month to measure the rate over. The latest complete month if omitted |
| `--scope <s>`        | `eligible` (default: usage a commitment could cover) or `all`        |

Global flags apply. See [CLI overview](/cli#global-flags).

### Examples

```bash
l4 commitments summary
l4 commitments summary --provider gcp
l4 commitments summary --period 2026-08 --scope all
l4 commitments summary --jq '.esr.data.totals.total_rate_pct'
```

The rate is reported alongside the share of spend it could be measured over. Where that share is
below 100%, the command says so rather than presenting a rate for the whole bill.

## list

```bash
l4 commitments list [flags]
```

One row per commitment across every account, soonest to expire first, with what a renewal protects
and what right-sizing would recover kept in separate columns. They are different amounts and are
never added: one is the loss avoided by renewing, the other is the saving from buying less.

### Flags

| Flag                    | Description                                          |
| ----------------------- | ---------------------------------------------------- |
| `--provider <id>`       | `aws`, `gcp` or `azure` (resolved if omitted)        |
| `--basis <b>`           | `net` (default, after your agreement) or `list`      |
| `--kind <k>`            | `ri`, `sp`, `cud`, `spend`                           |
| `--status <s>`          | `active`, `expiring`, `expired`, `cancelled`         |
| `--expiring-within <w>` | Only terms ending inside a window, for example `90d` |

A kind belonging to another provider is refused rather than sent. `--kind cud --provider aws` is a
valid request that returns nothing, and nothing is exactly what reads as "you hold none of these".

### Examples

```bash
l4 commitments list
l4 commitments list --basis list
l4 commitments list --kind ri --expiring-within 90d
l4 commitments list --provider gcp
l4 commitments list --jq '.data.rows[] | {id, expires: .expires_in_seconds}'
```

> **Warning**
>
> `--kind`, `--status` and `--expiring-within` shape the table, not the payload. Under `--json`, `--jq` or `--template` the command prints what the API returned, unfiltered, and says on stderr which flags it left out. Narrow the payload with `--jq` instead.

Every provider's rows arrive under `.data.rows[]`, so one `--jq` expression reads them all.

## view

```bash
l4 commitments view <id>
```

The full record for one commitment: kind, term, payment option, dates, state, utilization, coverage,
the accounts consuming it, and any recommendations attached to it.

A Savings Plan id is an ARN, so it contains colons and a slash. Quote it.

```bash
l4 commitments view ri-0a1b2c3d
l4 commitments view "arn:aws:savingsplans::111122223333:savingsplan/abc"
l4 commitments view ri-0a1b2c3d --json
l4 commitments view ri-0a1b2c3d --web
```

## utilization

```bash
l4 commitments utilization [flags]
```

Utilization is commitment hours used over commitment hours purchased: am I getting value from what I
bought. It is not coverage, which is eligible usage on a commitment over all eligible usage: how
exposed am I to on-demand rates.

> **Note**
>
> The two have different denominators and are never averaged together. The valuable reading is the mismatch. Full utilization alongside low coverage means the commitment is undersized, not that it is performing well: every eligible dollar above it is paying the on-demand rate.

Each service is measured on its own. EC2 and RDS contract in vCPU while Redshift, ElastiCache,
OpenSearch and MemoryDB contract in nodes, so a figure averaged across them would describe none of
them.

### Flags

| Flag                                          | Description                                                      |
| --------------------------------------------- | ---------------------------------------------------------------- |
| `--instrument <i>`                            | `ri` (default) or `sp`                                           |
| `--start <YYYY-MM-DD>` / `--end <YYYY-MM-DD>` | Window to measure                                                |
| `--granularity <g>`                           | `daily` (default) or `monthly`                                   |
| `--service <s>`                               | Restrict to one service, which also prints its day-by-day series |

### Examples

```bash
l4 commitments utilization
l4 commitments utilization --instrument sp
l4 commitments utilization --granularity monthly --start 2026-01-01
l4 commitments utilization --service ec2
```

A plan's day series carries no coverage column at all, for the reason in
[`not measured` is not zero](#not-measured-is-not-zero).

## plan

```bash
l4 commitments plan [flags]
```

On-demand spend no commitment covers, split by platform and volatility, beside the purchases that
would cover it.

Each slice is sized against its hourly floor rather than its average. Sizing against the average of
a volatile base commits to more than the base can sustain, which strands part of the commitment for
its whole term.

On Azure, `plan` lists the reservations and savings plans Azure recommends instead. LevelFour prices
each saving by applying Azure's discount to what the covered usage cost on demand on your bill over
the last 30 days.

| Flag              | Description                |
| ----------------- | -------------------------- |
| `--provider <id>` | `aws` or `azure`           |
| `--format <f>`    | `table` (default) or `csv` |

```bash
l4 commitments plan
l4 commitments plan --format csv > purchase-plan.csv
```

Buying is a savings recommendation, not a commitments command. On AWS, `plan` names the
recommendation ids, and [`l4 rec accept`](/cli/commands/recommendations/accept) acts on one. On
Azure, the **ID** column holds the key LevelFour stores each Azure recommendation under: its kind,
scope, SKU, region and term. Once someone raises a proposal as a purchase
in the dashboard, the **Raised** column names its `BUY-` recommendation, and `l4 rec accept` acts on
that.

## contracts

```bash
l4 commitments contracts
```

Marketplace and private-pricing relationships that bill like a commitment and appear in no provider
commitment view, with the contracted floor separated from the metered leg that bills on top of it.
You pay the floor whether or not you use it. The list covers every connected provider at once. On
DigitalOcean, what reserved products charge is the floor.

## Availability

These commands need an API release that serves the commitments routes. Against an organization whose
API does not yet, every one of them reports that and exits `0` rather than failing:

```text
Commitments are not yet available for your account.
```

## Related

* [`l4 commitments expiring`](/cli/commands/commitments/expiring): the CI gate
* [`l4 commitments renewal`](/cli/commands/commitments/renewal): sizing a repurchase
* [`l4 export commitments`](/cli/commands/export#commitments): the ledger as CSV or JSON
* [`l4 recommendations`](/cli/commands/recommendations): where a purchase is actually decided
* [Output formats](/cli/output-formats): `--json`, `--jq`, `--template` and `--quiet`
