What's new in CLI v2.1
dci v2.1 teaches the CLI your resource names: reports, budgets, and allocations can now be addressed — and tab-completed — by name instead of ID, and the completion scripts ship in every install channel. The v2.1.1 patch hardens completion with a hard guarantee: a Tab press can never touch the network or open a browser. v2.1 builds on the v2.0 ground-up refresh, summarized below.
Call resources by name
Anywhere a command takes a report, budget, or allocation ID, a name now works — quoted or not:
dci get-report "Monthly AWS Spend" # exact, case-insensitive, or unique-substring match
dci get-budget Team Backyard # quoting optional — the words are rejoined
dci open report Monthly AWS Spend # open, update-*, delete-* accept names too
Matching is forgiving but never guesses: exact name first, then case-insensitive, then a unique substring, then close typos. IDs still work everywhere and skip the lookup entirely.
- Ambiguity is an error, not a guess. If several resources share the name, the command fails (exit
2) listing every match asname (id)— re-run with the exact ID. - Unmatched names point you at the data.
NAME_NOT_FOUND(exit20) names thelist-*command to browse. - Destructive commands confirm the true target.
dci delete-report "old draft"resolves first, and the confirmation shows the resolved name and ID — a fuzzy match can never delete the wrong thing silently.
When you need precise control:
dci get-report --id <value> # treat the argument as a literal ID, skip the lookup
dci get-report --name <value> # force a name lookup even if it looks like an ID
DCI_NO_RESOLVE=1 dci ... # disable resolution entirely (for scripts)
Tab completes your data
Shell completion now offers your actual resource names, not just commands and flags:
$ dci get-report Mon<TAB>
Monthly AWS Spend Monthly GCP Spend
Names are served from a local cache that refreshes in the background — the Tab path itself never waits on the network. The first Tab in a fresh session tells you what's happening instead of staying silent, and the notice matches your session state: a warming cache says press Tab again in a few seconds, an expired session points at dci validate, and a signed-out CLI points at dci login. Set DCI_ACTIVE_HELP=0 to suppress the notices.
Type names bare when completing — the shell escapes spaces for you (dci get-report Monthly\ AWS\ Spend); completing inside an open quote is not supported by shell completion frameworks.
Completion installs itself now. Homebrew and the Linux .deb/.rpm packages install the bash, zsh, and fish scripts automatically; Scoop prints the one PowerShell profile line to add (WinGet users use the same line). Manual setup via source <(dci completion zsh) also works now — the generated script registers itself when sourced, which it previously did not.
Hardened in v2.1.1
- A Tab press can never open a browser or touch the network. Completion requests that can't be answered from local caches now return a short notice instead of falling through to a network fetch — previously, an expired local cache could escalate a Tab press all the way to an interactive sign-in.
- Partial command names complete.
dci st<TAB>completesstatus. get-anomalyworks with its UUID-shaped IDs — v2.1.0's name resolution mistook them for names and failed the lookup.- Multi-word names work unquoted in
dci open, matching the other commands.
Earlier: the v2.0 refresh
v2.0 was a ground-up refresh of the CLI experience for its two audiences: humans reading cloud costs in a terminal and AI agents driving the CLI programmatically. For the full gallery of terminal input/output comparisons, see CLI v2.0: before and after.
v2.0 unifies exit codes across all modes. Scripts that check $? != 0 are unaffected; scripts that branch on specific codes need the new taxonomy. Details in For scripts below.
For humans
Reports render as reports
Report results used to print as a flat database dump — one row per group × time period, with raw floats and epoch timestamps. In v2.0 the interactive table view pivots by default: groups as rows, time as columns, ranked by spend, with totals, a first→last trend column, and amounts carrying the report's currency sign, rounded to whole units.
Before (v1.x):
$ dci query < monthly.json
║ cost │ month │ service_description │ timestamp │ year ║
║ 239927.13841529994 │ 05 │ analytics │ 1.7462e+09 │ 2026 ║
║ 291018.65484701947 │ 06 │ analytics │ 1.7488e+09 │ 2026 ║
║ 345927.05937314965 │ 07 │ analytics │ 1.7514e+09 │ 2026 ║
║ 48875.47185098996 │ 05 │ pipelines │ 1.7462e+09 │ 2026 ║
...12 interleaved rows...
After (v2.0):
$ dci query < monthly.json
║ service_description │ 2026-05 │ 2026-06 │ 2026-07 │ total │ trend ║
║ analytics │ $239,927 │ $291,019 │ $345,927 │ $876,873 │ +44% ║
║ pipelines │ $48,875 │ $70,157 │ $95,806 │ $214,839 │ +96% ║
║ storage │ $83,219 │ $70,721 │ $53,925 │ $207,865 │ -35% ║
║ TOTAL │ $521,554 │ $567,513 │ $638,837 │ $1,727,905 │ +22% ║
In interactive terminals the pivot also shades period cells by magnitude — a heatmap that makes hot spots and movers readable at a glance (NO_COLOR or --heatmap=false disables it). Prefer the old layout? --flat restores flat rows, and --raw-numbers restores exact unformatted values. Hourly reports keep the hour on every row, and ranges with too many periods to scan stay flat unless you pass --pivot. See Running queries for all the result-shaping flags.
Listings you can actually read
Wide listings (anomalies return sixteen columns) used to crush every cell into … stubs and print unset values as a literal <nil>. v2.0 keeps the columns that render readably — identity (id, name) and date columns always survive — and tells you exactly what was hidden and how to get it back (-C, -M wrap, -W). Timestamps everywhere display as 2026-08-10 22:25 instead of epoch numbers or T00:00:00Z noise, budget amounts show their currency ($4,900), and an empty list simply prints No results.
Mistakes fail fast, with help
$ dci list-bugets # v1.x: 258 lines of help, exit code 0
$ dci list-bugets # v2.0:
Error: unknown command "list-bugets" (did you mean "list-budgets"?)
Interactive errors are now a single plain-text line — no more triple-printed messages with a usage dump. Setting an invalid customer context is rejected when you set it, instead of silently breaking every later command with 403s.
Jump to the console
dci open deep-links into the Cloud Intelligence™ console — dci open report <id>, budget, or allocation opens the resource in your browser (agents and pipes get the URL printed instead). dci docs prints every documentation entry point, and CSV export (--output csv) finally exists for spreadsheets.
For AI agents
v2.0 treats agents as first-class users. If you point Claude Code, Cursor, Codex, Gemini, Kiro, or opencode at dci, install the embedded skill with dci skill <agent> — it now ships a FinOps-baseline workflow (spend review → budgets → alerts → allocations) and a question-to-command map.
- Bounded output. An unlimited grouped query could return half a megabyte of rows straight into the context window. Agent mode now caps report results at 500 rows with explicit
rowsOmitted/rowsTotalmarkers;--max-rows 0restores everything. - Terse help.
--helpused to embed complete request/response schemas (query --helpwas ~15 KB). It's now ~2.4 KB, with schemas one flag away via--help-full. - Honest failure semantics. Successful deletes are no longer misreported as retryable upstream errors, client errors are never marked
retryable, and unknown request-body fields fail fast with the valid field list instead of being silently ignored by the API. - No hangs. Without credentials in CI or a sandbox, commands fail immediately with
AUTHENTICATION_REQUIREDand a pointer toDCI_API_KEYinstead of waiting on a browser login. - More context in results. Report results carry an explicit
currencyfield when the query config specifies one, and the pivot'strendcolumn gives agents the derived movement signal without recomputing it.--rows keyedreturns rows as schema-named objects — no more zipping positional arrays. Identical queries return identical row order.
For scripts
Exit codes are stable and identical in every mode:
| Code | Meaning |
|---|---|
0 | Success |
2 | Usage error (unknown command, flag, or body field) |
10 / 11 | Authentication / permission |
20 / 21 | Not found / conflict |
30 | Validation error or unconfirmed destructive command |
40 / 41 / 50 | Server error / network error / rate limited |
Previously, human and pipe invocations exited 1 for most failures, 4 for 404s — and a mistyped command exited 0. If a brand-new API field is rejected against a stale cached spec, retry with --rsh-no-cache or set DCI_SKIP_BODY_VALIDATION=1. Empty collections now serialize as [] instead of null, and old command names (e.g. id-of-asset) keep working as aliases for their new names (update-asset).
Upgrade
brew update && brew upgrade dci # macOS — or winget/scoop/apt/rpm per the install guide
dci upgrade # check your version from any install
dci skill update # refresh installed agent skills after upgrading
For installation, authentication, and the complete flag reference, start at the CLI guide. The cheat sheet has the one-page command summary.