Data Table Manager
n8n-io/n8n
Load before calling data-tables or parse-file. An agent skill from n8n-io/n8n.
End-to-end autopilot: inventory, generate, and submit WDK DDI API reference docs from a CSV file with no user interaction.
$ npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install MicrosoftDocs/windows-driver-docs-ddi ai-docs-autopilot --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/MicrosoftDocs/windows-driver-docs-ddi.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/ai-docs-autopilot .claude/skills/ai-docs-autopilot && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "ai-docs-autopilot" agent skill from https://github.com/MicrosoftDocs/windows-driver-docs-ddi/tree/staging/.github/skills/ai-docs-autopilot into .claude/skills/ai-docs-autopilot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-docs-autopilot", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/MicrosoftDocs/windows-driver-docs-ddi/tree/staging/.github/skills/ai-docs-autopilotType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install MicrosoftDocs/windows-driver-docs-ddi ai-docs-autopilot --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/MicrosoftDocs/windows-driver-docs-ddi.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.github/skills/ai-docs-autopilot .agents/skills/ai-docs-autopilot && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "ai-docs-autopilot" agent skill from https://github.com/MicrosoftDocs/windows-driver-docs-ddi/tree/staging/.github/skills/ai-docs-autopilot into .agents/skills/ai-docs-autopilot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-docs-autopilot", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install MicrosoftDocs/windows-driver-docs-ddi ai-docs-autopilot --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/MicrosoftDocs/windows-driver-docs-ddi.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.github/skills/ai-docs-autopilot .cursor/skills/ai-docs-autopilot && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "ai-docs-autopilot" agent skill from https://github.com/MicrosoftDocs/windows-driver-docs-ddi/tree/staging/.github/skills/ai-docs-autopilot into .cursor/skills/ai-docs-autopilot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-docs-autopilot", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/MicrosoftDocs/windows-driver-docs-ddi.git --path .github/skills/ai-docs-autopilot--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install MicrosoftDocs/windows-driver-docs-ddi ai-docs-autopilot --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/MicrosoftDocs/windows-driver-docs-ddi.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.github/skills/ai-docs-autopilot .gemini/skills/ai-docs-autopilot && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "ai-docs-autopilot" agent skill from https://github.com/MicrosoftDocs/windows-driver-docs-ddi/tree/staging/.github/skills/ai-docs-autopilot into .gemini/skills/ai-docs-autopilot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-docs-autopilot", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install MicrosoftDocs/windows-driver-docs-ddi ai-docs-autopilotInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/MicrosoftDocs/windows-driver-docs-ddi.git skills-src && mkdir -p .github/skills && cp -r skills-src/.github/skills/ai-docs-autopilot .github/skills/ai-docs-autopilot && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "ai-docs-autopilot" agent skill from https://github.com/MicrosoftDocs/windows-driver-docs-ddi/tree/staging/.github/skills/ai-docs-autopilot into .github/skills/ai-docs-autopilot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-docs-autopilot", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install MicrosoftDocs/windows-driver-docs-ddi ai-docs-autopilot --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/MicrosoftDocs/windows-driver-docs-ddi.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.github/skills/ai-docs-autopilot .opencode/skills/ai-docs-autopilot && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "ai-docs-autopilot" agent skill from https://github.com/MicrosoftDocs/windows-driver-docs-ddi/tree/staging/.github/skills/ai-docs-autopilot into .opencode/skills/ai-docs-autopilot/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-docs-autopilot", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
ai-docs-autopilotEnd-to-end autopilot: inventory, generate, and submit WDK DDI API reference docs from a CSV file with no user interaction.
AI Docs Autopilot is an agent skill from MicrosoftDocs/windows-driver-docs-ddi, published by the product's own GitHub organization. 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.
Its SKILL.md is about 9.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Documents & Office, covering CSV and tabular files. It works with Model Context Protocol. The repository describes itself as: The official Windows Driver Kit DDI reference documentation sources. The licence is CC-BY-4.0.
3 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 7515063. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
azFrom the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
dev.azure.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
AI Docs Autopilot loads about 9.7k tokens when it runs. Until then it costs about 58 tokens; SKILL.md has 3,666 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from MicrosoftDocs/windows-driver-docs-ddi at commit 7515063, republished under its CC-BY-4.0 licence (© MicrosoftDocs). 3,666 words, ~9,748 tokens.
.claude/skills/ai-docs-autopilot/SKILL.md (or your agent's skills folder).Run the full DDI documentation pipeline end-to-end with no user interaction. The agent inventories APIs from a CSV, generates documentation pages, and submits them as a PR — stopping only on error.
No local repo clones required. All repo interactions use the Azure DevOps REST API. OS source lookups use the substrate-mcp MCP server.
| 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) |
| Published Docs Repo (staging) | windows-driver-docs-ddi (branch: staging) |
| 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) |
| Output Path | {working_dir}\output\ |
| Style Guide | Read remotely from wdk-ddi repo: .github/copilot-instructions.md on main |
| User Alias | Auto-detected from CSV Owner column, $env:USERNAME, or az account show |
| Source Branch | Auto-generated as {user-alias}/{header}-update |
az) should be available for auth token acquisition. If not, the agent will prompt for an ADO Personal Access Token (PAT) once per session.substrate-mcp MCP server must be accessible for source code retrieval.microsoft.docs.mcp MCP server should be accessible for supplemental info (non-fatal if unavailable).This skill runs all three phases (inventory, generate, submit) in sequence with no user interaction between them. The process only stops if an error is encountered. Progress is reported to the console after each phase.
Track elapsed time and documents written across all three phases. Because each phase may run in a separate PowerShell process (variables don't survive between invocations), persist the start timestamp in a file so it can be read by later phases.
At the very beginning of the inventory.ps1 script, record the pipeline start time to a file in the working directory:
$pipelineStartTime = Get-Date
$pipelineStartTime.ToString('o') | Out-File -FilePath (Join-Path $workingDir '.pipeline-start') -Encoding utf8 -Force
$docsWrittenCount = 0Phase 2 is orchestrated by the agent (not a single script). After writing each documentation file, the agent must:
{workingDir}\.pipeline-start.Run this in the terminal after each file is written:
$start = [DateTime]::Parse((Get-Content '{workingDir}\.pipeline-start' -Raw).Trim())
$elapsed = (Get-Date) - $start
Write-Host "[$($elapsed.ToString('hh\:mm\:ss'))] Wrote doc {N}: {filename.md}"Alternatively, the agent can compute elapsed time from the stored timestamp itself and include it in its console message — the key requirement is that each doc written produces a visible [HH:MM:SS] Wrote doc N: filename progress line.
At the end of the submit.ps1 script, read the start time back and compute the total elapsed time:
$startFile = Join-Path $workingDir '.pipeline-start'
if (Test-Path $startFile) {
$pipelineStartTime = [DateTime]::Parse((Get-Content $startFile -Raw).Trim())
$totalElapsed = (Get-Date) - $pipelineStartTime
} else {
$totalElapsed = [TimeSpan]::Zero
}Include the elapsed time and document count in the final summary banner (see Phase 3, step 15).
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.
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.
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.
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.
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:
{workingDir}\inventory.ps1 containing all the logic from the Inventory Procedure below. Use the create_file tool to write the script — this auto-saves the file to disk immediately, avoiding any unsaved-buffer issues.powershell -ExecutionPolicy Bypass -File "{workingDir}\inventory.ps1"The script should accept no parameters — hardcode the {header}, {csvPath}, {workingDir}, and {userAlias} values directly into the generated script.
Write a single inventory.ps1 script that performs all of the following steps, then execute it.
Strip the .h extension from the user-provided header name to get {header} (e.g. soundwireclass.h → soundwireclass).
Resolve the user alias for branch naming ({user-alias}). The alias identifies who is submitting the PR, not who owns the APIs. Try these sources in order and use the first non-empty value:
a. The Windows username: $env:USERNAME.
b. The Azure CLI identity: az account show --query user.name -o tsv, extracting the alias portion before @.
The resolved alias is used later for the branch name {user-alias}/{header}-update. Hardcode it into the generated scripts.
Resolve paths. The user provides a CSV path. Derive the working directory from it. The script should validate the CSV exists and read it:
$ErrorActionPreference = "Stop"
$header = "{header}"
$csvPath = "{user-provided CSV path}"
$workingDir = Split-Path $csvPath -Parent
# Start the pipeline timer and persist it for later phases
$pipelineStartTime = Get-Date
$pipelineStartTime.ToString('o') | Out-File -FilePath (Join-Path $workingDir '.pipeline-start') -Encoding utf8 -Force
$docsWrittenCount = 0
if (-not (Test-Path $csvPath)) {
Write-Error "CSV not found at $csvPath."
exit 1
}Read the CSV:
$csvData = Import-Csv $csvPathThe 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.
Obtain ADO auth token. Try Azure CLI first, then fail with a clear message (PAT prompting cannot work inside a non-interactive script):
$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"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).
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):
# 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).
Classify each API into one of three categories:
stubs/main but no completed doc on mainmain — needs to be compared with the latest stub to identify changesOutput 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)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:
Output a per-file change summary (e.g. [+2 params, -1 param, ~1 param]) in the console results.
Write the updated CSV at the original CSV path. The format must be compatible with Phase 2:
filename,status
wdk-ddi-src/content/{header}/{filename1}.md,new
wdk-ddi-src/content/{header}/{filename2}.md,updateThe script writes both "new" and "update" entries. "Stub not found" entries are excluded.
Output a summary to the console:
{workingDir}{csvPath}After the script finishes, the agent should verify the CSV was written successfully. If the inventory found zero entries for documentation (all "stub not found"), stop with an error. Otherwise, proceed immediately to Phase 2 with no user prompt.
Generate complete API reference documentation pages for WDK DDI entities by combining stub files, OS source code declarations, and supplemental information from published docs.
Strip the .h extension from the user-provided header name to get {header} (e.g. soundwireclass.h → soundwireclass).
Resolve paths. The user provides a CSV path. Derive the working directory from it:
$csvPath = "{user-provided CSV path}"
if (-not (Test-Path $csvPath)) {
Write-Error "CSV not found at $csvPath. Please provide the CSV file first."
return
}
$workingDir = Split-Path $csvPath -Parent
$outputDir = Join-Path $workingDir "output"
Import-Csv $csvPathIf the CSV does not exist, stop with an error.
Obtain ADO auth token. Try Azure CLI first, then fall back to prompting for a PAT:
try {
$token = (az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv 2>$null)
if (-not $token) { throw "No token" }
$headers = @{ Authorization = "Bearer $token" }
} catch {
$pat = Read-Host "Enter ADO PAT (scope: Code Read)"
$base64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat"))
$headers = @{ Authorization = "Basic $base64" }
}
$adoBase = "https://dev.azure.com/cpubwin/drivers/_apis/git/repositories"Read the style guide remotely from the wdk-ddi repo to ensure all formatting rules are followed:
$styleGuide = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?path=.github/copilot-instructions.md&versionDescriptor.version=main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $headersParse the CSV file to get the list of target filenames. The CSV has a header row and one filename column with paths like wdk-ddi-src/content/{header}/{filename}.md.
Create the output directory if it doesn't exist; if it does, clear it:
if (Test-Path $outputDir) {
Remove-Item "$outputDir\*" -Force -ErrorAction SilentlyContinue
} else {
New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
}For each target file listed in the CSV, skip index.md (the header landing page is handled separately in step 8).
For each remaining target file:
Use the ADO REST API to check if the file already exists on main:
# List files on main branch
$mainFiles = 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 $headersIf the target filename appears in the listing, retrieve it from main and use its content as the starting point — preserve existing text, but always update ms.date to today's date when making any content changes. Only write the file to the output folder if you make changes. Do not copy unchanged files.
$content = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?path=wdk-ddi-src/content/{header}/{filename.md}&versionDescriptor.version=main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $headers
$content | Out-File -FilePath (Join-Path $outputDir "{filename.md}") -Encoding utf8If it does not exist on main, retrieve the stub from the stubs branch:
$content = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?path=wdk-ddi-src/content/{header}/{filename.md}&versionDescriptor.version=stubs/main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $headers
$content | Out-File -FilePath (Join-Path $outputDir "{filename.md}") -Encoding utf8Use the substrate-mcp MCP server to find the API's source declaration:
nf-soundwireclass-somefunc.md → SomeFunc)search_code(query="def:{ApiName}", ext="h")def: doesn't find it, try keyword search:search_code(query="{ApiName}", ext="h", path="**/{header}.h")get_file_content with a line range to retrieve the full declaration including:_In_, _Out_, _Inout_, _In_opt_, _Out_opt_, _Reserved_)Use the microsoft.docs.mcp server's microsoft_docs_search tool to search for any existing published docs or related conceptual content for the API:
microsoft_docs_search(query="{ApiName} WDK driver")Find 1-2 completed reference pages in the same header folder to use as formatting models. Use the ADO REST API to list files, then retrieve them:
# List existing completed docs of the same entity type in the {header} folder
$mainFiles = 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 $headers
# Filter for files matching the same prefix (e.g. "nf-") and pick 1-2Then read the model files:
$modelContent = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?path=wdk-ddi-src/content/{header}/{model-filename.md}&versionDescriptor.version=main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $headersIf no completed pages exist in the same folder, look in a related header folder. Read these model files to match their style.
Write the completed file to {outputDir}\{filename.md}. Follow these rules:
ai-usage: ai-assisted if not already presenttech.root to the same value as existing files in the same header folder. If no existing files in the folder (i.e. a brand-new API set), make an educated guess based on the header's source location, API naming patterns, and functionality (e.g. headers in minkernel/ are typically kernel, networking headers are netvista, storage headers are storage, etc.). Log the guessed value and add a note for the user: "NOTE: tech.root guessed as '{value}' — please verify this is correct."ms.date to today's date in MM/DD/YYYY format — both for new files and when updating existing files with changesreq.header, f1_keywords, api_name, topic_type are correctreq.header uses lowercase (e.g. classpnp.h). req.include-header uses sentence capitalization (e.g. Classpnp.h). Note that req.include-header does not always require a value — omit it or leave it empty when an include header is not applicable.req.construct-type for macros: If the source declaration is a preprocessor macro (#define), set req.construct-type: macro, not function. The file prefix remains nf- and the title should say "macro" (e.g. CLEAR_FLAG_NOFENCE macro (classpnp.h)).NE:wdbgexts._POOL_HEADER_FIELD_NAME), preserve that underscore in the UID of the generated document. However, all customer-facing content (title, description, headings, prose) must use the version without the leading underscore (e.g. POOL_HEADER_FIELD_NAME). For api_name: and f1_keywords:, include both versions — the underscored name and the public name — so the page is discoverable by either form.## -description
## -parameters (functions/callbacks/macros)
### -param {Name} [{direction}] subsection per parameter_In_ → [in]_Out_ → [out]_Inout_ → [in, out]_In_opt_ → [in, optional]_Out_opt_ → [out, optional]_Reserved_ → [in] with note "Reserved. Must be zero/NULL."&): If the macro implementation takes the address of a parameter (e.g. &(Flags)), describe the parameter as "An addressable {type} storage location (such as a variable or structure field)" rather than "A {type} value." A macro that takes &(param) requires an lvalue, not an arbitrary expression.## -struct-fields (structures only)
### -field {FieldName} subsection per fieldunion, it is still documented with the ns- file prefix and req.construct-type: structure. All prose (description, field descriptions, remarks, and cross-references from other pages) must call it a "structure", never a "union." The heading should read # {NAME} structure, not # {NAME} union.## -enum-fields (enumerations only)
### -field {ValueName}:{NumericValue} subsection per value (if numeric value is known)## -ioctlparameters (IOCTLs only)
## -returns (functions with return values)
## -remarks
Ex, or a number like 2, 3, or V2), reference the base entity and document only the extensions## -see-also
[**OtherFunc**](nf-{header}-otherfunc.md) for same-header APIs../ paths for cross-header: [**CrossFunc**](../otherheader/nf-otherheader-crossfunc.md)After writing each file, log progress with elapsed time. Run the following in the terminal (or compute the elapsed time from the stored timestamp and include it in the agent's console output):
$start = [DateTime]::Parse((Get-Content '{workingDir}\.pipeline-start' -Raw).Trim())
$elapsed = (Get-Date) - $start
Write-Host "[$($elapsed.ToString('hh\:mm\:ss'))] Wrote doc {N}: {filename.md}"The agent must track the running document count itself (incrementing after each file) and substitute {N} with the current count and {filename.md} with the actual filename.
**IoCreateFile***DesiredAccess*[title](/windows-hardware/drivers/...)cpp language tagHandle the header landing page (index.md). The landing page is automatically updated during the build to reflect the current API set, so it almost never needs manual editing once published.
index.md already exists on main of wdk-ddi or staging of the published docs repo using the ADO REST API:# Check wdk-ddi main
$mainItems = 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 $headers
# Check windows-driver-docs-ddi staging
$pubItems = Invoke-RestMethod -Uri "$adoBase/windows-driver-docs-ddi/items?scopePath=wdk-ddi-src/content/{header}/&recursionLevel=OneLevel&versionDescriptor.version=staging&versionDescriptor.versionType=branch&api-version=7.0" -Headers $headersindex.md appears in either listing, skip it — no action needed.index.md exists, retrieve the stub from the stubs branch and save it as index.md:$stubContent = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/items?path=wdk-ddi-src/content/{header}/na-{header}.md&versionDescriptor.version=stubs/main&versionDescriptor.versionType=branch&api-version=7.0" -Headers $headers
$stubContent | Out-File -FilePath (Join-Path $outputDir "index.md") -Encoding utf8index.md: After retrieving the stub, ensure the ## -description section follows this strict format:This header is used by {tech.root display name}. For more information, see: [{tech.root display name}](../{tech.root}/index.md).
Replace {tech.root display name} with the human-readable technology area name and {tech.root} with the tech.root value from the frontmatter (e.g. _netvista → [Networking](/windows-hardware/drivers/ddi/_netvista/)).-description. There must be no -remarks or -see-also sections in an index.md file.Close editor tabs and log progress. After all files have been written to {outputDir}, close all open editor tabs so the workspace is not cluttered with generated files. Run the VS Code command workbench.action.closeAllEditors to close them. Then display:
{outputDir}req.lib, req.dll, req.irql if not determinable from source)Then proceed immediately to Phase 3 with no user prompt.
Submit generated API reference documentation as a pull request to the wdk-ddi Azure DevOps repo using the ADO REST API.
No local repo clone required. Branch creation, file push, and PR creation are all done via the ADO REST API.
Strip the .h extension from the user-provided header name to get {header} (e.g. soundwireclass.h → soundwireclass).
Resolve paths. The user provides the CSV path. Derive the working and output directories:
$csvPath = "{user-provided CSV path}"
if (-not (Test-Path $csvPath)) {
Write-Error "CSV not found at $csvPath."
return
}
$workingDir = Split-Path $csvPath -Parent
$outputDir = Join-Path $workingDir "output"
$entries = Import-Csv $csvPathIf the CSV does not exist, stop with an error. Use the CSV entries to identify the API entities for the commit message and PR description.
Verify the output directory exists and contains files:
$outputFiles = Get-ChildItem -Path $outputDir -Filter "*.md" -ErrorAction SilentlyContinue
if (-not $outputFiles -or $outputFiles.Count -eq 0) {
Write-Error "No generated docs found in $outputDir. Generation phase may have failed."
return
}Obtain ADO auth token. Try Azure CLI first, then fall back to prompting for a PAT:
try {
$token = (az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv 2>$null)
if (-not $token) { throw "No token" }
$headers = @{ Authorization = "Bearer $token"; "Content-Type" = "application/json" }
} catch {
$pat = Read-Host "Enter ADO PAT (scope: Code Read+Write, PR Contribute)"
$base64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat"))
$headers = @{ Authorization = "Basic $base64"; "Content-Type" = "application/json" }
}
$adoBase = "https://dev.azure.com/cpubwin/drivers/_apis/git/repositories"Get the latest commit SHA on main. This is required as the oldObjectId for the push:
$refs = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/refs?filter=heads/main&api-version=7.0" -Headers $headers
$mainSha = $refs.value[0].objectIdDetermine change type for each file. Check which files already exist on main to set the correct changeType (add vs edit):
$mainFiles = 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 $headers
$existingNames = $mainFiles.value | ForEach-Object { Split-Path $_.path -Leaf }Build the push payload. Read each output file, base64-encode its content, and create the change entries:
$changes = @()
foreach ($file in $outputFiles) {
$contentBytes = [System.IO.File]::ReadAllBytes($file.FullName)
$base64Content = [Convert]::ToBase64String($contentBytes)
$repoPath = "/wdk-ddi-src/content/{header}/$($file.Name)"
$changeType = if ($file.Name -in $existingNames) { "edit" } else { "add" }
$changes += @{
changeType = $changeType
item = @{ path = $repoPath }
newContent = @{
content = $base64Content
contentType = "base64encoded"
}
}
}Generate the commit message. Use the CSV entries to list the API entity names:
Add/update API reference docs for {header}.h
Documented {N} API entities:
- {ApiName1} ({type})
- {ApiName2} ({type})
...
AI-assisted content generation.Log the push plan. Display:
add / edit){user-alias}/{header}-updateCreate or locate the branch. This step MUST be completed separately before the push in step 11. The branch must exist and point to a real commit on main before any push is attempted.
CRITICAL — Orphan commit prevention: The
oldObjectIdused in the push (step 11) determines the parent commit of the new commit. IfoldObjectIdis set to0000000000000000000000000000000000000000(all zeros), the ADO pushes API creates an orphan root commit with no parent. The resulting commit tree will contain ONLY the files in thechangesarray — all other repository files will appear as deletions in any PR diff. NEVER use all-zeros asoldObjectIdin the pushes API. Always use$mainShaor the branch's current commit SHA.
First, check if the branch already exists:
$branchRef = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/refs?filter=heads/{user-alias}/{header}-update&api-version=7.0" -Headers $headers
if ($branchRef.value.Count -gt 0) {
# Branch exists — use its current SHA
$branchSha = $branchRef.value[0].objectId
} else {
# Create the branch via the refs API (JSON array body)
$createBranchPayload = "[{`"name`":`"refs/heads/{user-alias}/{header}-update`",`"oldObjectId`":`"0000000000000000000000000000000000000000`",`"newObjectId`":`"$mainSha`"}]"
$refResult = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/refs?api-version=7.0" -Method Post -Headers $headers -Body $createBranchPayload
$branchSha = $refResult.value[0].newObjectId
}Important: The
POST /refsendpoint requires the body to be a JSON array, not an object. UsingConvertTo-Jsonon a single hashtable wraps it in an{}object, which the API rejects. Either manually construct the JSON string or wrap the hashtable in@(...)and verify the output is[{...}].
Validate that $branchSha is a real commit SHA (40 hex chars, not all zeros) before proceeding:
if (-not $branchSha -or $branchSha -eq "0000000000000000000000000000000000000000") {
Write-Error "Branch SHA is null or all-zeros. Branch creation may have failed. Aborting."
return
}
Write-Host "Branch SHA for push: $branchSha"Push the commit to the branch. The oldObjectId in refUpdates MUST be $branchSha (which equals $mainSha for a newly created branch). This tells ADO to create a new commit whose parent is $branchSha, inheriting all existing files from that commit's tree:
$pushBody = @{
refUpdates = @(
@{
name = "refs/heads/{user-alias}/{header}-update"
oldObjectId = $branchSha # MUST be a real SHA, never all-zeros
}
)
commits = @(
@{
comment = "<generated commit message>"
changes = $changes
}
)
} | ConvertTo-Json -Depth 10
$pushResult = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/pushes?api-version=7.0" -Method Post -Headers $headers -Body $pushBodyDo NOT combine branch creation and push into a single pushes API call. Always create the branch first (step 10), then push to it (step 11).
Verify the push. Confirm the new commit has a parent (is not orphaned) by checking the commit details:
$newCommitId = $pushResult.commits[0].commitId
$commitDetail = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/commits/$newCommitId?api-version=7.0" -Headers $headers
if (-not $commitDetail.parents -or $commitDetail.parents.Count -eq 0) {
Write-Error "FATAL: Push created an orphan commit (no parent). The branch must be deleted and recreated. This means oldObjectId was wrong."
# Clean up: delete the broken branch
$deletePayload = "[{`"name`":`"refs/heads/{user-alias}/{header}-update`",`"oldObjectId`":`"$($commitDetail.commitId)`",`"newObjectId`":`"0000000000000000000000000000000000000000`"}]"
Invoke-RestMethod -Uri "$adoBase/wdk-ddi/refs?api-version=7.0" -Method Post -Headers $headers -Body $deletePayload
Write-Error "Broken branch deleted. Please retry the submission."
return
}
Write-Host "Commit $newCommitId verified — parent: $($commitDetail.parents[0])"Create a pull request targeting main:
$prBody = @{
sourceRefName = "refs/heads/{user-alias}/{header}-update"
targetRefName = "refs/heads/main"
title = "{user-alias}/{header}-update: API reference docs for {header}.h"
description = "<PR description with header name, API entity list, AI-assisted note>"
} | ConvertTo-Json
$prResult = Invoke-RestMethod -Uri "$adoBase/wdk-ddi/pullrequests?api-version=7.0" -Method Post -Headers $headers -Body $prBodyThe PR description should include:
ai-usage: ai-assisted metadata is set in each file)Display the PR URL to the user:
$prUrl = "https://dev.azure.com/cpubwin/drivers/_git/wdk-ddi/pullrequest/$($prResult.pullRequestId)"
Write-Host "PR created: $prUrl"Final summary. Read the persisted start time and compute the total elapsed time. Include this in the submit script:
$startFile = Join-Path $workingDir '.pipeline-start'
if (Test-Path $startFile) {
$pipelineStartTime = [DateTime]::Parse((Get-Content $startFile -Raw).Trim())
$totalElapsed = (Get-Date) - $pipelineStartTime
} else {
$totalElapsed = [TimeSpan]::Zero
}
Write-Host ""
Write-Host "========================================"
Write-Host " Autopilot Complete"
Write-Host "========================================"
Write-Host "Total elapsed time : $($totalElapsed.ToString('hh\:mm\:ss'))"
Write-Host "Documents written : $docsWrittenCount"
Write-Host "========================================"The $docsWrittenCount value must be hardcoded into the generated submit.ps1 script by the agent (since the agent tracks the count during Phase 2).
Then display:
{outputDir}{prUrl}{totalElapsed} | Documents written: {docsWrittenCount}© MicrosoftDocs, CC-BY-4.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .github/skills/ai-docs-autopilot of MicrosoftDocs/windows-driver-docs-ddi.
Open the folder on GitHubat commit 7515063
AI Docs Autopilot next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| AI Docs Autopilot this skillMicrosoftDocs/windows-driver-docs-ddi | 316 | — | ~9.7k | Automated safety check: Pass | CC-BY-4.0 | |
| Data Table Managern8n-io/n8n | 207k | — | ~2.3k | Automated safety check: Pass | Custom licence | |
| Dv Datamicrosoft/Dataverse-skills | 242 | — | ~4.8k | Automated safety check: Notes | MIT | |
| Scenario Admin Analyticsscenario-labs/skills | 913 | — | ~2.9k | Automated safety check: Pass | MIT | |
| DatalionHybridAIOne/hybridclaw | 158 | — | ~2.8k | Automated safety check: Pass | MIT | |
| Jinshujuinfometa/workbuddyskills | 344 | — | ~2k | Automated safety check: Pass | MIT |
n8n-io/n8n
Load before calling data-tables or parse-file. An agent skill from n8n-io/n8n.
microsoft/Dataverse-skills
Record-level CRUD and bulk operations — create, update, delete, upsert, CSV import, multi-table foreign-key loads, AI-generated sample data.
scenario-labs/skills
A skill your agent uses when answering Scenario admin analytics questions about Creative Unit consumption, most-used models, usage by user or project, AI adoption observability, cached usage data…
HybridAIOne/hybridclaw
A skill your agent uses for DataLion workflows such as listing, reading, creating, or editing projects, inspecting data sources, importing Excel or CSV data, working with reports and report tabs and…
infometa/workbuddyskills
通过金数据(Jinshuju,jinshuju.net)MCP 操作用户托管在金数据平台上的在线表单:创建 / 复制 / 编辑表单与主题,含自动判分的考试表单、选项计分的测评表单;查询、新增(单条或批量)、更新、删除、批量修改数据;用上传凭证上传本地图片或文件;查询账户套餐额度与团队成员。仅在用户操作其金数据平台数据时使用——触发信号:提到 金数据 / Jinshuju /…
infometa/workbuddyskills
通过金数据(Jinshuju,jinshuju.net)MCP 操作用户托管在金数据平台上的数据表格:创建 / 编辑数据表与列(含自动计算的公式列);查询、新增(单条或批量)、更新、批量更新、删除行数据;用上传凭证把本地文件写入附件列;查询账户套餐额度与团队成员。仅在用户操作其金数据数据表时使用——触发信号:提到 金数据表格 / Jinshuju 表格 /…
MicrosoftDocs/windows-driver-docs-ddi
Generate WDK DDI API reference documentation pages from source code and stubs.
MicrosoftDocs/windows-driver-docs-ddi
Inventory and classify APIs listed in a pre-provided CSV for a WDK header file.
MicrosoftDocs/windows-driver-docs-ddi
Submit generated WDK DDI API reference documentation as a PR to the wdk-ddi repo.
Works with
Categories
End-to-end autopilot: inventory, generate, and submit WDK DDI API reference docs from a CSV file with no user interaction. AI Docs Autopilot is an agent skill from MicrosoftDocs/windows-driver-docs-ddi, published by the product's own GitHub organization. End-to-end autopilot: inventory, generate, and submit WDK DDI API reference docs from a CSV file with no user interaction.
AI Docs Autopilot fits situations like: : running the full doc pipeline unattended; auto-generating and submitting DDI docs.
Run `npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a claude-code`. Or copy the skill folder (.github/skills/ai-docs-autopilot in MicrosoftDocs/windows-driver-docs-ddi) into .claude/skills/ai-docs-autopilot in your project. Claude Code loads it when a task matches its description.
Run `npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a codex`. Or copy the skill folder (.github/skills/ai-docs-autopilot in MicrosoftDocs/windows-driver-docs-ddi) into .agents/skills/ai-docs-autopilot in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add MicrosoftDocs/windows-driver-docs-ddi --skill ai-docs-autopilot -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ai-docs-autopilot, .gemini/skills/ai-docs-autopilot, .github/skills/ai-docs-autopilot and .opencode/skills/ai-docs-autopilot in your project.
Going by SKILL.md and its folder, AI Docs Autopilot needs the command-line tools its instructions call (az).
SKILL.md names 1 domain. In commands or code: dev.azure.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
AI Docs Autopilot is published under the CC-BY-4.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 9.7k tokens (SKILL.md is roughly 39k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with AI Docs Autopilot: Data Table Manager (n8n-io/n8n, 207k stars), Dv Data (microsoft/Dataverse-skills, 242 stars), Scenario Admin Analytics (scenario-labs/skills, 913 stars) and Datalion (HybridAIOne/hybridclaw, 158 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
MicrosoftDocs (a GitHub organization, an official publisher) maintains it in MicrosoftDocs/windows-driver-docs-ddi, which has 316 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on July 25, 2026.
Source: MicrosoftDocs/windows-driver-docs-ddi on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.