ai-docs-inventory
$
npx mdskill add MicrosoftDocs/windows-driver-docs-ddi/ai-docs-inventoryInventory and classify APIs from CSV for documentation generation.
- Cross-references API filenames against existing docs and stubs.
- Integrates with Azure DevOps REST API for data retrieval.
- Classifies status based on content presence in specified repos.
- Outputs finalized CSV ready for the documentation generation tool.
SKILL.md
.github/skills/ai-docs-inventoryView on GitHub ↗
---
name: ai-docs-inventory
description: 'Inventory and classify APIs listed in a pre-provided CSV for a WDK header file. Use when: inventorying a header, classifying APIs, validating a CSV for doc generation, checking what needs to be documented.'
argument-hint: 'Specify a header name (e.g. soundwireclass) and the path to the CSV file.'
---
# Inventory Header
Read a pre-provided CSV of target API filenames, cross-reference each entry against existing docs, stubs, and published content via the ADO REST API, classify their status, and finalize the CSV for use with the `ai-docs-generate` skill.
**No local repo clones required.** All repo interactions use the Azure DevOps REST API.
## Parameters
| Parameter | Value |
|-----------|-------|
| ADO Org | `https://dev.azure.com/cpubwin` |
| ADO Project | `drivers` |
| Docs Repo | `wdk-ddi` (branches: `main`, `stubs/main`) |
| Published Docs Repo | `wdk-ddi-build` (branch: `live`) |
| Content Path | `wdk-ddi-src/content/{header}/` |
| Stubs Branch | `stubs/main` (default; user may specify alternate like `stubs/release-amethyst`) |
| Header Name | Provided by the user (e.g. `soundwireclass`) |
| CSV Input | Provided by the user at any local path (e.g. `D:\work\soundwireclass.csv`) |
| Working Directory | Derived from CSV path (parent folder of the CSV file) |
## Prerequisites
- The user provides a header name and a path to a CSV file. **That is the only user requirement.**
- Azure CLI (`az`) should be available for auth token acquisition. If not, the agent will prompt for an ADO Personal Access Token (PAT) once per session.
## File Naming Conventions
Map each API entity to a filename using these prefixes:
| Prefix | Type | Example |
|--------|------|---------|
| `nf` | Function | `nf-soundwireclass-somefunc.md` |
| `ns` | Structure | `ns-soundwireclass-some_struct.md` |
| `ne` | Enumeration | `ne-soundwireclass-some_enum.md` |
| `nc` | Callback | `nc-soundwireclass-evt_some_callback.md` |
| `ni` | IOCTL | `ni-soundwireclass-ioctl_some_code.md` |
| `nn` | Interface | `nn-soundwireclass-isome_interface.md` |
| `nl` | Class | `nl-soundwireclass-some_class.md` |
The filename pattern is: `{prefix}-{header}-{api_name_lowercase}.md`
Where `{header}` is the header name without the `.h` extension.
### Header Landing Page
On the stubs branch, the header landing page is always named `na-{header}.md`. When it is copied to `wdk-ddi-src/content/{header}/` on the `main` branch, it is renamed to `index.md`. In the published docs repo, it also appears as `index.md`. When cross-referencing, check for `na-{header}.md` on the stubs branch and `index.md` on `main` and in the published docs repo.
### Legacy Filename Exceptions
Some existing files in the published docs repo or on `main` may have non-standard filenames (e.g. an extra underscore like `ns-header-_struct_name.md` instead of `ns-header-struct_name.md`). These are historical naming errors. **Do not rename existing files** — doing so would break published links. When cross-referencing, also check for these variant filenames. For **new** APIs, always use the approved naming convention.
## Execution Strategy
**Write all PowerShell logic into a single self-contained `.ps1` script file, then execute it in one terminal call.** Do NOT run ADO REST calls or variable assignments as separate interactive terminal commands — PowerShell variables are lost between terminal invocations and long-running commands may time out and get moved to the background, breaking the workflow.
The pattern is:
1. Create a script file at `{workingDir}\inventory.ps1` containing all the logic from the Procedure below.
2. Execute it in a single terminal call: `powershell -ExecutionPolicy Bypass -File "{workingDir}\inventory.ps1"`
3. Parse the script's console output to present results to the user.
The script should accept no parameters — hardcode the `{header}`, `{csvPath}`, and `{workingDir}` values directly into the generated script.
## Procedure
Write a single `inventory.ps1` script that performs all of the following steps, then execute it.
1. Strip the `.h` extension from the user-provided header name to get `{header}` (e.g. `soundwireclass.h` → `soundwireclass`).
2. **Resolve paths.** The user provides a CSV path. Derive the working directory from it. The script should validate the CSV exists and read it:
```powershell
$ErrorActionPreference = "Stop"
$header = "{header}"
$csvPath = "{user-provided CSV path}"
$workingDir = Split-Path $csvPath -Parent
if (-not (Test-Path $csvPath)) {
Write-Error "CSV not found at $csvPath."
exit 1
}
```
Read the CSV:
```powershell
$csvData = Import-Csv $csvPath
```
The CSV has a header row. Look for a column containing file paths (commonly `FilePath` or `filename`) with values like `wdk-ddi-src/content/{header}/{filename}.md`. Filter to rows with valid `.md` paths.
3. **Obtain ADO auth token.** Try Azure CLI first, then fail with a clear message (PAT prompting cannot work inside a non-interactive script):
```powershell
$token = (az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv 2>$null)
if (-not $token) {
Write-Error "Failed to get ADO token. Run 'az login' first, or set `$env:ADO_PAT before running."
exit 1
}
$h = @{ Authorization = "Bearer $token" }
$adoBase = "https://dev.azure.com/cpubwin/drivers/_apis/git/repositories"
```
4. For each entry in the CSV, extract the target filename from the path (e.g. `wdk-ddi-src/content/{header}/nf-soundwireclass-somefunc.md` → `nf-soundwireclass-somefunc.md`).
5. **List all files in the directory on each branch** (one API call per branch, not per file). This detects legacy filename variants (see [Legacy Filename Exceptions](#legacy-filename-exceptions)):
```powershell
# List files on main branch of wdk-ddi
try {
$r1 = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?scopePath=wdk-ddi-src/content/{header}/&recursionLevel=OneLevel&versionDescriptor.version=main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $h
$mainFiles = @($r1.value | Where-Object { $_.path -like "*.md" } | ForEach-Object { Split-Path $_.path -Leaf })
} catch { $mainFiles = @() }
# List files on stubs branch of wdk-ddi
try {
$r2 = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?scopePath=wdk-ddi-src/content/{header}/&recursionLevel=OneLevel&versionDescriptor.version=stubs/main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $h
$stubFiles = @($r2.value | Where-Object { $_.path -like "*.md" } | ForEach-Object { Split-Path $_.path -Leaf })
} catch { $stubFiles = @() }
# List files on live branch of wdk-ddi-build (published docs)
try {
$r3 = Invoke-RestMethod -Uri "$adoBase/wdk-ddi-build/items?scopePath=wdk-ddi-src/content/{header}/&recursionLevel=OneLevel&versionDescriptor.version=live&versionDescriptor.versionType=branch&api-version=7.0" -Headers $h
$pubFiles = @($r3.value | Where-Object { $_.path -like "*.md" } | ForEach-Object { Split-Path $_.path -Leaf })
} catch { $pubFiles = @() }
Write-Host "Main: $($mainFiles.Count) files, Stubs: $($stubFiles.Count) files, Published: $($pubFiles.Count) files"
```
Compare each expected filename against the directory listings. If a file exists with a minor variant (e.g. `ns-header-_struct_name.md` instead of `ns-header-struct_name.md`), treat it as a match — the doc exists under the legacy name. **Use the legacy filename in the CSV** (do not rename it).
a. Check if the file exists on `main` of `wdk-ddi` (look for the filename in `$mainFiles`).
b. Check if a stub exists on the stubs branch (look for the filename in `$stubFiles`).
c. Check if the file exists on `live` of the published docs repo `wdk-ddi-build` (look for the filename in `$pubFiles`).
6. Classify each API into one of three categories:
- **new**: Stub exists on `stubs/main` but no completed doc on `main`
- **update**: File already exists on `main` — needs to be compared with the latest stub to identify changes
- **stub not found**: No stub and no existing doc
7. **Output grouped results** to the console for the agent to parse and present:
```
=== New (ready to document) ===
nf-soundwireclass-somefunc.md (function)
ns-soundwireclass-some_struct.md (structure)
=== Update (existing doc, needs diff) ===
nf-soundwireclass-otherfunc.md (function) [+2 params, -1 param, ~1 param]
=== Stub not found ===
ne-soundwireclass-some_enum.md (enumeration)
```
8. **Diff existing docs against stubs.** For each "update" entry, fetch the existing doc from `main` and the latest stub from `stubs/main` via the ADO REST API. Compare the parameter/field/value sections to identify:
- **Added** parameters, fields, or enum values (present in stub but not in existing doc)
- **Removed** parameters, fields, or enum values (present in existing doc but not in stub)
- **Modified** parameters, fields, or enum values (present in both but with different types or descriptions)
Output a per-file change summary (e.g. `[+2 params, -1 param, ~1 param]`) in the console results.
9. **Write the updated CSV** at the original CSV path. The format must be compatible with the `ai-docs-generate` skill:
```csv
filename,status
wdk-ddi-src/content/{header}/{filename1}.md,new
wdk-ddi-src/content/{header}/{filename2}.md,update
```
The script writes both "new" and "update" entries. "Stub not found" entries are excluded.
10. **Output a summary** to the console:
- Number of APIs in the CSV by type
- Number selected for documentation
- Working directory: `{workingDir}`
- CSV file location: `{csvPath}`
After the script finishes, the agent should:
11. Open the CSV in the editor:
```powershell
code $csvPath
```
12. **Continue or stop.** Ask the user:
> Inventory complete. Press **y** to continue to generate API docs, or type **n** to stop.
- If the user types **y**: automatically invoke the `ai-docs-generate` skill, passing the same header name and CSV path. Behave as if the user typed `/ai-docs-generate {header}.h {workingDir}`.
- If the user types **n**: stop and tell them they can run it later with: `/ai-docs-generate {header}.h {workingDir}`
> **Tip:** To run all three steps (inventory → generate → submit) with no interaction, use the `ai-docs-autopilot` skill instead.
More from MicrosoftDocs/windows-driver-docs-ddi
- ai-docs-autopilot'End-to-end autopilot: inventory, generate, and submit WDK DDI API reference docs from a CSV file with no user interaction. Use when: running the full doc pipeline unattended, auto-generating and submitting DDI docs.'
- ai-docs-generate'Generate WDK DDI API reference documentation pages from source code and stubs. Use when: writing API docs, generating reference pages, documenting a header, creating DDI documentation.'
- ai-docs-submit'Submit generated WDK DDI API reference documentation as a PR to the wdk-ddi repo. Use when: submitting docs, creating a PR for DDI docs, pushing documentation changes.'