---
name: mongodb-index-usage
description: >
  Analyse MongoDB index usage across a whole cluster to find unused indexes and
  measure the disk space they waste, using $indexStats via the mongosh CLI (never
  the MongoDB MCP). Groups databases into cohorts by their collection set (tenant
  clones vs singletons like `shared`), reasons globally per cohort, and reports
  per-collection volumetry (data / disk / index). Use when the user says
  /mongodb-index-usage, 'index inutilisés mongo', 'analyse les index mongodb',
  'quels index sont inutiles', 'combien d espace prennent les index', 'index usage
  mongo', 'unused indexes', 'trouve les index morts', 'volumétrie des collections
  mongo', or wants an analysis of which MongoDB indexes are unused and how much
  disk they occupy. This skill is read-only: it reports, it never drops indexes.
argument-hint: "[dev|prod] [--collection <name>] [--include-db <db>] [--min-age-days N] [--sample-dbs N]"
allowed-tools:
  - Bash
  - Read
  - AskUserQuestion
---

Detect unused MongoDB indexes cluster-wide and quantify the disk they waste. All
the heavy lifting is done by `pysae-ai-tools mongo index-usage`, which connects
with **mongosh** (not the MongoDB MCP), walks every database/collection, and:

- groups databases into **cohorts** by their collection signature — the tenant
  fleet (many databases sharing the same collections, hence the same indexes) vs
  singleton databases with a unique shape (e.g. `shared`);
- reasons **globally within each cohort**: an index is only flagged UNUSED when it
  received **zero operations across every measured database** of its cohort;
- reports, per `<database>.<collection>`, the three volumetries — **data**
  (uncompressed), **disk** (compressed on-disk) and **index** (on-disk index) —
  plus the reclaimable space of each dead index.

By default it measures **every database** for exact numbers.

## Required tools

- `mongo-tools`
- `aws`

Run `pysae-ai-tools tools require mongo-tools aws` before starting; if it exits non-zero, abort and report the install command from stderr to the user.

## Workflow

1. **Pick the environment** from `$ARGUMENTS` (`dev` or `prod`; default `dev`).
   Map it to `MONGO_URI_DEV` / `MONGO_URI_PROD`.

2. **Resolve the URI into the environment** (never print it — it contains
   credentials):
   ```bash
   eval "$(pysae-ai-tools env resolve --set MONGO_URI_PROD)" || exit 1
   ```

3. **Run the analysis.** Pass the URI through `--uri-env` so it stays out of the
   process list. This is read-only (`$collStats` / `$indexStats` / `listIndexes`).
   On a large cluster the exhaustive scan takes several minutes — run it in the
   background and tell the user it is working:
   ```bash
   pysae-ai-tools mongo index-usage --uri-env MONGO_URI_PROD --json > report.json
   ```
   Forward any relevant `$ARGUMENTS` flags: `--collection`, `--include-db`,
   `--exclude-db`, `--min-age-days`. Only add `--sample-dbs N` if the user
   explicitly asks for a faster, approximate pass — the default (exact, all
   databases) is what they usually want.

   - **Target one collection** with `--collection <name>` (repeatable): every
     database holding it becomes a single cohort and only that collection is
     measured — fast, and the natural way to answer "is index X on collection Y
     used anywhere?".
   - The scan streams a live progress gauge on stderr and is **safe to
     interrupt** with Ctrl-C (it is read-only and stops mongosh cleanly).

4. **Report the findings** (from JSON or text). This skill is **read-only and
   analytical only** — present the data, never propose or perform index drops, and
   do not emit `dropIndex` commands. Per cohort, summarise:
   - the **UNUSED** indexes ranked by size, with their cohort coverage
     (`used in X/Y measured dbs`) and observation window, and the total space they
     occupy;
   - the **volumetry** per `<database>.<collection>` (data / disk / index) when
     relevant;
   - which indexes are **USED** (and how marginally — e.g. used in only 2/300 dbs),
     **CONSTRAINT** (unique/TTL) and **KEEP** (`_id_`), stated as facts;
   - **INCONCLUSIVE** indexes as "observation window too short to conclude";
   - **homogeneity anomalies** (an index missing from some cohort members) — often
     a migration that didn't run everywhere.

   Stop at the analysis. If the user then wants to act on it, that is a separate,
   explicit decision on their side.

## Caveats to always state

- Operation counts are **summed across every replica-set member** (the tool opens
  a directConnection to each host from `hello().hosts` and adds up `$indexStats`),
  so reads served by secondaries are counted. Check the report line
  `ops summed across N/M members` — if `N < M`, some member was unreachable and
  usage may be undercounted, so a zero-op result is less certain.
- `$indexStats.accesses.ops` resets when a node restarts/fails over. Verdicts are
  gated on the **most recent** stats reset seen across nodes: a zero-op index is
  only UNUSED once every observation window is ≥ `--min-age-days` (otherwise
  INCONCLUSIVE).
- An index can show zero ops yet be structurally required (unique constraint, TTL
  expiry) — those are reported as CONSTRAINT/KEEP, not UNUSED.

$ARGUMENTS
