Summary
azd core has a documentation generation pipeline (cli/azd/docs/docgen.go) that produces a unified Markdown CLI reference, published to MicrosoftDocs/azure-dev-docs-pr during each release. We need an equivalent story for azd extensions, so that each extension can automatically generate and publish a command reference.
Current state — how core azd docgen works
-
cli/azd/docs/docgen.go — a standalone main package that calls azd.NewRootCmd(true, nil, nil) to build the Cobra command tree with static help text (no runtime state). It walks the tree recursively with genMarkdownFile(), emitting a single azd.md with front-matter, headings per command, flags, examples, code fences, "See also" cross-links, and "Back to top" navigation.
-
ADO pipeline (eng/pipelines/templates/stages/build-and-test.yml) runs go run docgen.go from cli/azd/docs/, copies the output into a docs pipeline artifact.
-
Publish step (eng/pipelines/templates/steps/publish-cli-docs.yml) clones azure-sdk/azure-dev-docs-pr, copies azd.md → articles/azure-developer-cli/reference.md, and opens a PR to MicrosoftDocs/azure-dev-docs-pr.
Key coupling to core azd
docgen.go imports azd/cmd directly to get the root Cobra command — this is a Go compile-time dependency on core azd's entire command tree.
- Extensions don't expose their Cobra tree in the same way; instead they use
azdext.NewExtensionRootCommand() + azdext.NewMetadataCommand() which can output a structured JSON metadata blob.
- The markdown formatting logic (front-matter, code fences, placeholder escaping, link mapping, "See also" sections) is generic and could work with any Cobra tree — it doesn't depend on azd-specific types beyond
*cobra.Command.
What extensions already provide
Every extension that declares the metadata capability already has:
- A
metadata subcommand (via azdext.NewMetadataCommand) that outputs full JSON with command names, short/long descriptions, usage lines, examples, flags (name, type, default, valid values, hidden, deprecated), and subcommands.
- A Cobra command tree internally (via
azdext.NewExtensionRootCommand).
Options
Option A: Extend core docgen.go to accept an extension binary path
Add a CLI flag to the existing docgen.go so it can be pointed at an extension binary:
go run docgen.go # existing behavior (core azd)
go run docgen.go -extension ./my-extension # new: generate docs for extension
How it would work:
- Run
<extension-binary> metadata to get the JSON command metadata.
- Reconstruct a Cobra tree from the metadata (or parse the JSON directly).
- Feed it through the existing
genMarkdownFile() with a customizable front-matter template.
Pros:
- Single doc-generation tool for the entire ecosystem — one place to fix formatting bugs.
- Leverages the existing, battle-tested markdown generation logic.
- Extensions don't need any new code; they already have
metadata.
Cons:
- Couples extension doc generation to the core azd repo and its Go module. Extension teams must clone/reference the azd repo to generate docs.
- The metadata JSON intentionally omits inherited flags and "See also" relationships — the reconstructed Cobra tree may be lossy compared to the real one.
- Requires the extension binary to be pre-built (or
go run-able) at doc-generation time.
- Front-matter and formatting may need to differ per extension (different docs repo, different author, etc.).
Option B: azd x docgen command in the developer extension
Add a docgen subcommand to azd x (the extension developer toolkit) that generates docs for the extension in the current directory:
cd cli/azd/extensions/azure.ai.agents
azd x docgen # generates md/ reference
azd x docgen --output ./docs # custom output dir
How it would work:
azd x docgen builds the extension, runs <binary> metadata, converts the JSON metadata tree to Markdown using shared formatting logic (extracted from docgen.go or reimplemented in azdext).
- Output format and front-matter are configured via
extension.yaml fields (e.g., docs.title, docs.author, docs.frontMatter).
Pros:
- Natural developer experience — extension authors already use
azd x build, azd x test, etc.
- No dependency on core azd's Go module; the formatting logic lives in
azdext or a shared package.
- Works for any extension (first-party or third-party) without cloning the azd repo.
- Front-matter and output structure can be configured per extension via
extension.yaml.
Cons:
- Requires implementing (or extracting) the markdown generation logic into the
azdext package or the developer extension.
- Requires
azd to be installed to generate docs (may complicate CI for standalone extension repos).
- The
azd x developer extension is not yet distributed widely; external extension authors may not have it.
Option C: Code-generate a docgen.go into the extension
azd x generates a self-contained docs/docgen.go file inside the extension folder, similar to how the core azd one works — importing the extension's own cmd package:
azd x init-docgen # scaffolds docs/docgen.go + CI pipeline
How it would work:
- Generate a
docs/docgen.go that imports the extension's internal/cmd (or wherever the root command is) and calls genMarkdownFile() from a shared library.
- Optionally scaffold a GitHub Actions workflow (
.github/workflows/publish-docs.yml) that runs go run docs/docgen.go and opens a PR to the extension's docs repo.
Pros:
- Each extension is fully self-contained — no dependency on
azd or azd x at doc-generation time.
- Extension teams own their pipeline and can customize freely.
- Works identically to how core azd does it — familiar pattern.
Cons:
- Code duplication: every extension gets its own copy of the markdown formatting logic (unless a shared Go library is published and imported).
- Scaffold drift: if the markdown format changes, all extensions need to regenerate or manually update.
- Requires the extension's
cmd package to be importable (some extensions may have complex init requirements).
- More setup burden per extension (each needs its own docs repo, pipeline config, etc.).
Option D: Shared azdext/docgen library + per-extension docgen.go (hybrid)
Extract the markdown generation logic from cli/azd/docs/docgen.go into a reusable library package (e.g., pkg/azdext/docgen). Each extension writes a minimal docs/docgen.go that imports this library:
package main
import (
"github.com/azure/azure-dev/cli/azd/pkg/azdext/docgen"
"my-extension/internal/cmd"
)
func main() {
root := cmd.NewRootCommand()
docgen.Generate(root, docgen.Options{
Title: "Azure AI Agents Extension Reference",
Author: "...",
})
}
How it would work:
- Extract
genMarkdownFile, genMarkdownCustom, addCodeFencesToSampleCommands, escapePlaceholders, etc. into pkg/azdext/docgen as exported functions.
- Publish the azd Go module with semver tags (already done via
cli/azd/vX.Y.Z tags).
- Each extension adds a thin
docs/docgen.go + optionally a CI workflow.
Pros:
- Single source of truth for formatting logic — updates propagate via Go module versioning.
- Each extension controls its own front-matter, output path, and CI pipeline.
- Minimal boilerplate per extension.
- Works with the existing Go module versioning strategy.
Cons:
- Extensions take a Go module dependency on core azd's
pkg/azdext/docgen — version coupling.
- Still requires per-extension CI setup (though a template could be provided).
- The shared library needs to be generic enough to handle different command tree shapes.
Recommendation
Option B (azd x docgen) for the best developer experience, with Option D (shared library) as a companion for extensions that need standalone CI.
Option B gives the immediate win: extension developers already use azd x and the metadata infrastructure is already there. Option D provides a clean path for extensions in separate repos that need to generate docs in their own CI without depending on azd being installed.
CI / Publishing considerations
Each extension may publish docs to a different repo. The publish step should be configurable:
- Target repo (e.g.,
MicrosoftDocs/azure-ai-agents-docs-pr)
- Target path within the repo
- Branch naming convention
- PR title template
This could be driven by extension.yaml fields or a separate docs.yaml config.
References
- Core docgen:
cli/azd/docs/docgen.go
- ADO build step:
eng/pipelines/templates/stages/build-and-test.yml:188-194
- ADO publish step:
eng/pipelines/templates/steps/publish-cli-docs.yml
- Extension metadata generator:
cli/azd/pkg/azdext/metadata_generator.go
- Extension metadata command:
cli/azd/pkg/azdext/extension_commands.go:44-61
- Extension metadata types:
cli/azd/pkg/extensions/metadata.go
Summary
azd core has a documentation generation pipeline (
cli/azd/docs/docgen.go) that produces a unified Markdown CLI reference, published toMicrosoftDocs/azure-dev-docs-prduring each release. We need an equivalent story for azd extensions, so that each extension can automatically generate and publish a command reference.Current state — how core azd docgen works
cli/azd/docs/docgen.go— a standalonemainpackage that callsazd.NewRootCmd(true, nil, nil)to build the Cobra command tree with static help text (no runtime state). It walks the tree recursively withgenMarkdownFile(), emitting a singleazd.mdwith front-matter, headings per command, flags, examples, code fences, "See also" cross-links, and "Back to top" navigation.ADO pipeline (
eng/pipelines/templates/stages/build-and-test.yml) runsgo run docgen.gofromcli/azd/docs/, copies the output into adocspipeline artifact.Publish step (
eng/pipelines/templates/steps/publish-cli-docs.yml) clonesazure-sdk/azure-dev-docs-pr, copiesazd.md→articles/azure-developer-cli/reference.md, and opens a PR toMicrosoftDocs/azure-dev-docs-pr.Key coupling to core azd
docgen.goimportsazd/cmddirectly to get the root Cobra command — this is a Go compile-time dependency on core azd's entire command tree.azdext.NewExtensionRootCommand()+azdext.NewMetadataCommand()which can output a structured JSON metadata blob.*cobra.Command.What extensions already provide
Every extension that declares the
metadatacapability already has:metadatasubcommand (viaazdext.NewMetadataCommand) that outputs full JSON with command names, short/long descriptions, usage lines, examples, flags (name, type, default, valid values, hidden, deprecated), and subcommands.azdext.NewExtensionRootCommand).Options
Option A: Extend core
docgen.goto accept an extension binary pathAdd a CLI flag to the existing
docgen.goso it can be pointed at an extension binary:How it would work:
<extension-binary> metadatato get the JSON command metadata.genMarkdownFile()with a customizable front-matter template.Pros:
metadata.Cons:
go run-able) at doc-generation time.Option B:
azd x docgencommand in the developer extensionAdd a
docgensubcommand toazd x(the extension developer toolkit) that generates docs for the extension in the current directory:How it would work:
azd x docgenbuilds the extension, runs<binary> metadata, converts the JSON metadata tree to Markdown using shared formatting logic (extracted fromdocgen.goor reimplemented inazdext).extension.yamlfields (e.g.,docs.title,docs.author,docs.frontMatter).Pros:
azd x build,azd x test, etc.azdextor a shared package.extension.yaml.Cons:
azdextpackage or the developer extension.azdto be installed to generate docs (may complicate CI for standalone extension repos).azd xdeveloper extension is not yet distributed widely; external extension authors may not have it.Option C: Code-generate a
docgen.gointo the extensionazd xgenerates a self-containeddocs/docgen.gofile inside the extension folder, similar to how the core azd one works — importing the extension's owncmdpackage:azd x init-docgen # scaffolds docs/docgen.go + CI pipelineHow it would work:
docs/docgen.gothat imports the extension'sinternal/cmd(or wherever the root command is) and callsgenMarkdownFile()from a shared library..github/workflows/publish-docs.yml) that runsgo run docs/docgen.goand opens a PR to the extension's docs repo.Pros:
azdorazd xat doc-generation time.Cons:
cmdpackage to be importable (some extensions may have complex init requirements).Option D: Shared
azdext/docgenlibrary + per-extensiondocgen.go(hybrid)Extract the markdown generation logic from
cli/azd/docs/docgen.gointo a reusable library package (e.g.,pkg/azdext/docgen). Each extension writes a minimaldocs/docgen.gothat imports this library:How it would work:
genMarkdownFile,genMarkdownCustom,addCodeFencesToSampleCommands,escapePlaceholders, etc. intopkg/azdext/docgenas exported functions.cli/azd/vX.Y.Ztags).docs/docgen.go+ optionally a CI workflow.Pros:
Cons:
pkg/azdext/docgen— version coupling.Recommendation
Option B (
azd x docgen) for the best developer experience, with Option D (shared library) as a companion for extensions that need standalone CI.Option B gives the immediate win: extension developers already use
azd xand the metadata infrastructure is already there. Option D provides a clean path for extensions in separate repos that need to generate docs in their own CI without depending onazdbeing installed.CI / Publishing considerations
Each extension may publish docs to a different repo. The publish step should be configurable:
MicrosoftDocs/azure-ai-agents-docs-pr)This could be driven by
extension.yamlfields or a separatedocs.yamlconfig.References
cli/azd/docs/docgen.goeng/pipelines/templates/stages/build-and-test.yml:188-194eng/pipelines/templates/steps/publish-cli-docs.ymlcli/azd/pkg/azdext/metadata_generator.gocli/azd/pkg/azdext/extension_commands.go:44-61cli/azd/pkg/extensions/metadata.go