Skip to content

Commit 9cf637b

Browse files
authored
Migrate cobra command examples from Long: prose to Example: field (#38946)
1 parent 6995b39 commit 9cf637b

42 files changed

Lines changed: 189 additions & 218 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# ADR-38946: Use Cobra's `Example:` Field for Command Usage Examples
2+
3+
**Date**: 2026-06-12
4+
**Status**: Draft
5+
6+
## Context
7+
8+
The CLI in `pkg/cli/` defines ~36 cobra commands, and historically every command embedded its usage examples as hand-written prose inside the `Long:` description field under an `Examples:` heading. Cobra provides a dedicated `Example:` field that is rendered separately in `--help` output and, critically, is consumed by `cobra/doc.GenMarkdownTree()` for documentation generation. Because the examples lived inside `Long:`, generated documentation could not surface them in the expected structured location, and the examples were not addressable for testing or tooling. This PR migrates all command definitions to use the native `Example:` field. The change is large by line count but mechanical and repetitive (moving example blocks between two struct fields).
9+
10+
## Decision
11+
12+
We will store all cobra command usage examples in the native cobra `Example:` field rather than embedding them as `Examples:` prose inside the `Long:` field. Non-example prose that previously followed the `Examples:` section (e.g., "Workflow specifications:", "The command will:") is moved back into `Long:` where it belongs. Tests that previously asserted example strings appeared in `cmd.Long` are updated to assert against `cmd.Example`. This aligns the codebase with cobra's intended API contract, restores correct `GenMarkdownTree()` documentation output, and makes examples independently inspectable.
13+
14+
## Alternatives Considered
15+
16+
### Alternative 1: Keep examples in `Long:` prose
17+
18+
Leave the existing convention untouched and continue embedding examples under an `Examples:` heading inside `Long:`. Rejected because it breaks `cobra/doc.GenMarkdownTree()` documentation generation, keeps examples untestable as a distinct field, and diverges from cobra's documented usage of the `Example:` field.
19+
20+
### Alternative 2: Custom help template / renderer
21+
22+
Introduce a custom cobra help/usage template that parses the `Examples:` section out of `Long:` at render time. Rejected as unnecessary complexity: it reimplements behavior cobra already provides natively, adds a maintenance burden, and still would not feed `GenMarkdownTree()` correctly.
23+
24+
## Consequences
25+
26+
### Positive
27+
- `cobra/doc.GenMarkdownTree()` produces correct documentation with examples in their structured location.
28+
- Examples become independently testable and inspectable via `cmd.Example`.
29+
- Command definitions follow cobra's intended API convention, improving consistency across all ~36 commands.
30+
31+
### Negative
32+
- Large, repetitive diff (36 command files plus 8 secondary prose fixes and 5 test updates) that touches many files at once and must be reviewed for correctness.
33+
- A standing convention contributors must remember to follow for new commands; without a lint check, regressions can reappear.
34+
35+
### Neutral
36+
- `--help` output formatting shifts slightly because the `Example:` field is rendered under cobra's own "Examples:" section heading rather than inline within the long description.
37+
- Test assertions referencing example content move from `cmd.Long` to `cmd.Example`.
38+
39+
---
40+
41+
*This is a DRAFT ADR generated by the [Design Decision Gate](https://github.com/github/gh-aw/actions/runs/27447688258) workflow. The PR author must review, complete, and finalize this document before the PR can merge.*

pkg/cli/add_command.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,6 @@ func NewAddCommand(validateEngine func(string) error) *cobra.Command {
5959
This command adds workflows directly without interactive prompts. Use 'add-wizard'
6060
for a guided setup that configures secrets, creates a pull request, and more.
6161
62-
Examples:
63-
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/daily-repo-status # Add workflow directly
64-
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/repo-assist # Add package from repository root aw.yml
65-
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/packages/repo-assist # Add package from nested aw.yml
66-
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor@v1.0.0 # Add with version
67-
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/workflows/ci-doctor.md@main
68-
` + string(constants.CLIExtensionPrefix) + ` add https://github.com/githubnext/agentics/blob/main/workflows/ci-doctor.md
69-
` + string(constants.CLIExtensionPrefix) + ` add https://example.com/my-workflow.md # Add workflow from any HTTPS URL
70-
` + string(constants.CLIExtensionPrefix) + ` add https://example.com/workflow.json # Import JSON workflow definition
71-
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --create-pull-request --force
72-
` + string(constants.CLIExtensionPrefix) + ` add ./my-workflow.md # Add local workflow
73-
` + string(constants.CLIExtensionPrefix) + ` add ./*.md # Add all local workflows
74-
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --dir .github/workflows/shared # Add to .github/workflows/shared/
75-
7662
Workflow specifications:
7763
- Two parts: "owner/repo[@version]" (loads repository-root aw.yml package)
7864
- Three+ parts without .md: "owner/repo/folder[@version]" (loads nested aw.yml package when present)
@@ -96,6 +82,19 @@ Note: In GitHub Enterprise repos, shorthand source specs resolve on your enterpr
9682
Use full https://github.com/... source URLs for other public github.com workflows.
9783
Note: To create a new workflow from scratch, use the 'new' command instead.
9884
Note: For guided interactive setup, use the 'add-wizard' command instead.`,
85+
Example: ` ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/daily-repo-status # Add workflow directly
86+
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/repo-assist # Add package from repository root aw.yml
87+
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/packages/repo-assist # Add package from nested aw.yml
88+
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor@v1.0.0 # Add with version
89+
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/workflows/ci-doctor.md@main
90+
` + string(constants.CLIExtensionPrefix) + ` add https://github.com/githubnext/agentics/blob/main/workflows/ci-doctor.md
91+
` + string(constants.CLIExtensionPrefix) + ` add https://example.com/my-workflow.md # Add workflow from any HTTPS URL
92+
` + string(constants.CLIExtensionPrefix) + ` add https://example.com/workflow.json # Import JSON workflow definition
93+
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --create-pull-request --force
94+
` + string(constants.CLIExtensionPrefix) + ` add ./my-workflow.md # Add local workflow
95+
` + string(constants.CLIExtensionPrefix) + ` add ./*.md # Add all local workflows
96+
` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --dir .github/workflows/shared # Add to .github/workflows/shared/
97+
`,
9998
Args: func(cmd *cobra.Command, args []string) error {
10099
if len(args) < 1 {
101100
return fmt.Errorf("missing workflow specification\n\nUsage:\n %s <workflow>...\n\nExamples:\n %[1]s githubnext/agentics/daily-repo-status Add from repository\n %[1]s ./my-workflow.md Add local workflow\n\nRun '%[1]s --help' for more information", cmd.CommandPath())

pkg/cli/add_wizard_command.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,6 @@ This command walks you through:
2727
2828
Use 'add' for non-interactive workflow addition.
2929
30-
Examples:
31-
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics # Guided setup for repository-root aw.yml package
32-
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/packages/repo-assist # Guided setup for nested aw.yml package
33-
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/daily-repo-status # Guided setup
34-
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/ci-doctor@v1.0.0 # Guided setup with version
35-
` + string(constants.CLIExtensionPrefix) + ` add-wizard ./my-workflow.md # Guided setup for local workflow
36-
` + string(constants.CLIExtensionPrefix) + ` add-wizard https://example.com/my-workflow.md # Guided setup from any HTTPS URL
37-
` + string(constants.CLIExtensionPrefix) + ` add-wizard https://example.com/workflow.json # Import JSON workflow definition with guided setup
38-
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/ci-doctor --engine copilot # Pre-select engine
39-
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/ci-doctor --skip-secret # Skip secret prompt
40-
4130
Workflow specifications:
4231
- Two parts: "owner/repo[@version]" (loads repository-root aw.yml package)
4332
- Three+ parts without .md: "owner/repo/folder[@version]" (loads nested aw.yml package when present)
@@ -55,6 +44,16 @@ Note: In GitHub Enterprise repos, shorthand specs resolve on your enterprise hos
5544
For github/*, githubnext/*, and microsoft/*, shorthand resolves on github.com.
5645
Use full https://github.com/... URLs when sourcing other public github.com workflows.
5746
Note: To create a new workflow from scratch, use the 'new' command instead.`,
47+
Example: ` ` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics # Guided setup for repository-root aw.yml package
48+
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/packages/repo-assist # Guided setup for nested aw.yml package
49+
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/daily-repo-status # Guided setup
50+
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/ci-doctor@v1.0.0 # Guided setup with version
51+
` + string(constants.CLIExtensionPrefix) + ` add-wizard ./my-workflow.md # Guided setup for local workflow
52+
` + string(constants.CLIExtensionPrefix) + ` add-wizard https://example.com/my-workflow.md # Guided setup from any HTTPS URL
53+
` + string(constants.CLIExtensionPrefix) + ` add-wizard https://example.com/workflow.json # Import JSON workflow definition with guided setup
54+
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/ci-doctor --engine copilot # Pre-select engine
55+
` + string(constants.CLIExtensionPrefix) + ` add-wizard githubnext/agentics/ci-doctor --skip-secret # Skip secret prompt
56+
`,
5857
Args: func(cmd *cobra.Command, args []string) error {
5958
if len(args) < 1 {
6059
return errors.New("missing workflow specification\n\nRun 'gh aw add-wizard --help' for usage information")

pkg/cli/audit.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,8 @@ Each argument accepts:
6565
When a job URL is provided (single-run mode only):
6666
- If a step number is included (#step:7:1), extracts that specific step's output
6767
- If no step number, finds and extracts the first failing step's output
68-
- Saves job logs to the output directory
69-
70-
Examples:
71-
` + string(constants.CLIExtensionPrefix) + ` audit 1234567890 # Audit run with ID 1234567890
68+
- Saves job logs to the output directory`,
69+
Example: ` ` + string(constants.CLIExtensionPrefix) + ` audit 1234567890 # Audit run with ID 1234567890
7270
` + string(constants.CLIExtensionPrefix) + ` audit https://github.com/owner/repo/actions/runs/1234567890 # Audit from run URL
7371
` + string(constants.CLIExtensionPrefix) + ` audit https://github.com/owner/repo/actions/runs/1234567890/job/9876543210 # Audit job and extract first failing step
7472
` + string(constants.CLIExtensionPrefix) + ` audit https://github.com/owner/repo/actions/runs/1234567890/job/9876543210#step:7:1 # Extract step 7 output

pkg/cli/audit_diff_command.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@ analyzes their data, and produces a diff showing:
4040
- Anomaly flags (new denied domains, previously-denied now allowed)
4141
- MCP tool invocation changes (new/removed tools, call count and error count diffs)
4242
- Run metrics comparison (token usage, duration, turns) when cached data is available
43-
- Detailed token usage breakdown (input/output/cache + AI Credits) from firewall proxy
44-
45-
Examples:
46-
` + string(constants.CLIExtensionPrefix) + ` audit diff 12345 12346 # Compare two runs
43+
- Detailed token usage breakdown (input/output/cache + AI Credits) from firewall proxy`,
44+
Example: ` ` + string(constants.CLIExtensionPrefix) + ` audit diff 12345 12346 # Compare two runs
4745
` + string(constants.CLIExtensionPrefix) + ` audit diff 12345 12346 12347 12348 # Compare base against 3 runs
4846
` + string(constants.CLIExtensionPrefix) + ` audit diff 12345 12346 --format markdown # Markdown output for PR comments
4947
` + string(constants.CLIExtensionPrefix) + ` audit diff 12345 12346 --json # JSON for CI integration

pkg/cli/checks_command.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,8 @@ JSON output includes two state fields:
9292
branch-protection or account-gate statuses fail
9393
9494
Use required_state as the authoritative CI verdict in repos that have optional
95-
deployment integrations posting commit statuses alongside required CI checks.
96-
97-
Examples:
98-
` + string(constants.CLIExtensionPrefix) + ` checks 42 # Classify checks for PR #42
95+
deployment integrations posting commit statuses alongside required CI checks.`,
96+
Example: ` ` + string(constants.CLIExtensionPrefix) + ` checks 42 # Classify checks for PR #42
9997
` + string(constants.CLIExtensionPrefix) + ` checks 42 --repo owner/repo # Specify repository
10098
` + string(constants.CLIExtensionPrefix) + ` checks 42 --json # Output in JSON format`,
10199
Args: cobra.ExactArgs(1),

pkg/cli/cli_consistency_help_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestAuditCommandDescriptionsAreConsistent(t *testing.T) {
2323
func TestTrialCommandUsesStandardExamplesHeading(t *testing.T) {
2424
cmd := NewTrialCommand(func(string) error { return nil })
2525

26-
assert.Contains(t, cmd.Long, "Examples:", "trial long help should use the standard examples heading")
26+
assert.NotEmpty(t, cmd.Example, "trial command should use cobra's Example field for examples")
2727
assert.NotContains(t, cmd.Long, "Single workflow:", "trial long help should avoid custom example section headings")
2828
assert.NotContains(t, cmd.Long, "Multiple workflows (for comparison):", "trial long help should avoid custom example section headings")
2929
assert.NotContains(t, cmd.Long, "Workflows from different repositories:", "trial long help should avoid custom example section headings")

pkg/cli/completion_command.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@ Tab completion provides:
2424
- Directory path completion for --dir flag
2525
- Helpful descriptions for workflows when available
2626
27-
Supported shells: bash, zsh, fish, PowerShell
28-
29-
Examples:
30-
# Install completions automatically (detects your shell)
27+
Supported shells: bash, zsh, fish, PowerShell`,
28+
Example: ` # Install completions automatically (detects your shell)
3129
gh aw completion install
3230
3331
# Generate completion script for bash
@@ -81,10 +79,8 @@ Supported shells:
8179
- Bash: Installs to ~/.bash_completion.d/ or /etc/bash_completion.d/
8280
- Zsh: Installs to ~/.zsh/completions/
8381
- Fish: Installs to ~/.config/fish/completions/
84-
- PowerShell: Provides instructions to add to PowerShell profile
85-
86-
Examples:
87-
gh aw completion install # Auto-detect and install
82+
- PowerShell: Provides instructions to add to PowerShell profile`,
83+
Example: ` gh aw completion install # Auto-detect and install
8884
gh aw completion install --verbose # Show detailed installation steps`,
8985
RunE: func(cmd *cobra.Command, args []string) error {
9086
verbose, _ := cmd.Flags().GetBool("verbose")
@@ -107,10 +103,8 @@ Supported shells:
107103
- Bash: Removes from ~/.bash_completion.d/ or /etc/bash_completion.d/
108104
- Zsh: Removes from ~/.zsh/completions/
109105
- Fish: Removes from ~/.config/fish/completions/
110-
- PowerShell: Provides instructions to remove from PowerShell profile
111-
112-
Examples:
113-
gh aw completion uninstall # Auto-detect and uninstall
106+
- PowerShell: Provides instructions to remove from PowerShell profile`,
107+
Example: ` gh aw completion uninstall # Auto-detect and uninstall
114108
gh aw completion uninstall --verbose # Show detailed uninstallation steps`,
115109
RunE: func(cmd *cobra.Command, args []string) error {
116110
verbose, _ := cmd.Flags().GetBool("verbose")

pkg/cli/completion_command_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,11 @@ func TestCompletionCommand_Examples(t *testing.T) {
129129
cmd := NewCompletionCommand()
130130

131131
// Verify examples are present for all shells
132-
assert.Contains(t, cmd.Long, "gh aw completion install")
133-
assert.Contains(t, cmd.Long, "gh aw completion bash")
134-
assert.Contains(t, cmd.Long, "gh aw completion zsh")
135-
assert.Contains(t, cmd.Long, "gh aw completion fish")
136-
assert.Contains(t, cmd.Long, "gh aw completion powershell")
132+
assert.Contains(t, cmd.Example, "gh aw completion install")
133+
assert.Contains(t, cmd.Example, "gh aw completion bash")
134+
assert.Contains(t, cmd.Example, "gh aw completion zsh")
135+
assert.Contains(t, cmd.Example, "gh aw completion fish")
136+
assert.Contains(t, cmd.Example, "gh aw completion powershell")
137137
}
138138

139139
func TestCompletionCommand_ValidArgs(t *testing.T) {

pkg/cli/deploy_command.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ func NewDeployCommand(validateEngine func(string) error) *cobra.Command {
2828
Short: "Deploy agentic workflows to a target repository using a pull request",
2929
Long: `Deploy one or more workflows to a target repository by combining clone, update, add, compile, and pull request creation.
3030
31-
The command clones the target repository, updates existing workflows from source, adds the specified workflows, recompiles lock files with purge enabled, and opens a pull request.
32-
33-
Examples:
34-
` + string(constants.CLIExtensionPrefix) + ` deploy githubnext/agentics/ci-doctor --repo owner/repo
31+
The command clones the target repository, updates existing workflows from source, adds the specified workflows, recompiles lock files with purge enabled, and opens a pull request.`,
32+
Example: ` ` + string(constants.CLIExtensionPrefix) + ` deploy githubnext/agentics/ci-doctor --repo owner/repo
3533
` + string(constants.CLIExtensionPrefix) + ` deploy githubnext/agentics/repo-assist githubnext/agentics/ci-doctor --repo owner/repo --force
3634
` + string(constants.CLIExtensionPrefix) + ` deploy ./my-workflow.md --repo owner/repo`,
3735
Args: validateDeployArgs,

0 commit comments

Comments
 (0)