Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions cli/azd/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,21 @@ func (a *myAction) Run(ctx context.Context) (*actions.ActionResult, error) {
- **Shell-safe output**: When emitting shell commands in user-facing messages (e.g., `cd <path>`), quote paths that may contain spaces. Use `fmt.Sprintf("cd %q", path)` or conditionally wrap in quotes
- **Consistent JSON types**: When adding fields to JSON output (`--output json`), match the types used by similar fields across commands. Don't mix `*time.Time` and custom timestamp wrappers (e.g., `*RFC3339Time`) in the same API surface

### CLI UX & Style

When working on CLI output, terminal UX, spinners, progress states, colors, or prompts for **core azd flows**, you **MUST read** the style guide before making any changes or recommendations:

📄 **`cli/azd/docs/style-guidelines/azd-style-guide.md`** (full path from repo root)

This file is the authoritative reference for core azd terminal UX patterns including:
- Progress report states (`(✓) Done`, `(x) Failed`, `(!) Warning`, `(-) Skipped`)
- Spinner type (bar-fill `|=======|`)
- Color conventions (`WithSuccessFormat`, `WithErrorFormat`, `WithHighLightFormat`, etc.)
- User input patterns (text input, list select, yes/no confirm)
- Prompt styling (`?` marker in bold blue, `[Type ? for hint]`, post-submit states)

> **Note**: This style guide covers **core azd flows only**. Separate guidelines for agentic flows and extension-specific UX will be provided in dedicated files in the future. Do not apply core azd patterns to agentic or extension flows without a dedicated style reference.

### Code Organization

- **Import order**: stdlib → external → azure/azd internal → local
Expand Down Expand Up @@ -307,6 +322,7 @@ go build

Feature-specific docs are in `docs/` — refer to them as needed. Some key docs include:

- `docs/style-guidelines/azd-style-guide.md` - CLI style guide (colors, spinners, progress states, terminal UX)
- `docs/style-guidelines/new-azd-command.md` - Adding new commands
- `docs/extensions/extension-framework.md` - Extension development using gRPC extension framework
- `docs/style-guidelines/guiding-principles.md` - Design principles
Expand Down
258 changes: 217 additions & 41 deletions cli/azd/docs/style-guidelines/azd-style-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

This style guide establishes standards for code, user experience, testing, and documentation across the Azure Developer CLI project. Following these guidelines ensures consistency, maintainability, and a high-quality user experience.

> **Scope**: This guide covers **core azd flows** only. Separate guidelines for agentic flows and extension-specific UX will be provided in dedicated files in the future.

## Code Style Guidelines

### Go Conventions
Expand Down Expand Up @@ -70,7 +72,7 @@ func (s *Service) Run(ctx context.Context) error {

### Progress Reports

Progress reports provide real-time feedback during multi-step operations. Use progress reports to:
Progress reports provide real-time feedback during a single command's execution, showing the status of individual steps as they happen. Use progress reports to:

- Show status of long-running commands
- Display individual service provisioning/deployment states
Expand All @@ -81,79 +83,214 @@ Progress reports provide real-time feedback during multi-step operations. Use pr
Items in a progress report list can be in one of five states:

1. **Loading**: `|=== | [Verb] Message goes here`
- Indicates operation in progress
- Shows loading bar animation
- Indicates operation in progress; animated bar-fill spinner in gray (`WithGrayFormat`)

2. **Done**: `(✓) Done: [Verb] Message goes here`
- Green checkmark indicates successful completion
- Past tense verb
- Green checkmark via `WithSuccessFormat`; use past tense verb

3. **Failed**: `(✗) Failed: [Verb] Message goes here`
- Red X indicates error
- Include specific error message below
3. **Failed**: `(x) Failed: [Verb] Message goes here`
- Red `x` via `WithErrorFormat`; include specific error message below

4. **Warning**: `(!) Warning: [Verb] Message goes here`
- Yellow exclamation for non-blocking issues
- Command continues but user should be aware
- Yellow exclamation via `WithWarningFormat`; non-blocking, command continues

5. **Skipped**: `(-) Skipped: [Verb] Message goes here`
- Gray dash indicates intentionally skipped step
- Different from failed - this is expected behavior
- Gray dash via `WithGrayFormat`; intentionally skipped (not a failure)

#### Quick Reference

**Progress report state → prefix → color function:**

| State | Prefix | Color Function | Notes |
| -------- | -------------- | ------------------- | ------------------------- |
| Loading | `\|=== \|` | `WithGrayFormat` | Animated bar-fill spinner |
| Done | `(✓) Done:` | `WithSuccessFormat` | Past tense verb |
| Failed | `(x) Failed:` | `WithErrorFormat` | Follow with error detail |
| Warning | `(!) Warning:` | `WithWarningFormat` | Non-blocking issue |
| Skipped | `(-) Skipped:` | `WithGrayFormat` | Expected, not a failure |

**Log type → prefix → color function:**

| Log Type | Prefix | Color Function | When to use |
| ---------- | ----------------- | ------------------- | ------------------------------------------ |
| Success | `SUCCESS:` | `WithSuccessFormat` | Command completed its primary goal |
| Error | `ERROR:` | `WithErrorFormat` | Command failed; top-level failure message |
| Warning | `WARNING:` | `WithWarningFormat` | Non-fatal issue the user should know about |

#### Progress Report Guidelines

- **Indentation**: Progress items are always indented under the main command
- **Hierarchy**: Sub-steps appear indented under parent steps
- **Verb consistency**: Use present progressive for loading, past tense for completed
- **Contextual information**: Include resource names, identifiers when relevant

#### Examples
#### Example

**Success scenario:**
**Failure scenario** (shows how multiple states compose with error detail):

```
Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

(✓) Done: Creating App Service Plan: plan-r2w2adrz3rvwxu
(✓) Done: Creating Log Analytics workspace: log-r2w2adrz3rvwxu
(✓) Done: Creating Application Insights: appi-r2w2adrz3rvwxu
(✓) Done: Creating App Service: app-api-r2w2adrz3rvwxu
(x) Failed: Creating Cosmos DB: cosmos-r2w2adrz3rvwxu
The '{US} West US 2 (westus)' region is currently experiencing high demand
and cannot fulfill your request. Failed to create Cosmos DB account.

ERROR: Unable to complete provisioning of Azure resources, 'azd up' failed
```

**Failure scenario:**
> Colors: Title → `WithBold`. `(✓) Done:` → `WithSuccessFormat`. `(x) Failed:` and error detail → `WithErrorFormat`. `ERROR:` line → `WithErrorFormat`.

### Success / Error / Warning Logs

These logs represent the final outcome of a command, displayed after execution completes. Standard logs (Success, Error, Warning) use an **all-caps prefix** followed by a colon to separate the log type from the message.

All logs should:

- Be **succinct**
- Be **human legible**
- **Provide a path forward** when possible

There are some specific edge cases where the log prefix is not required.

#### When to Use Each Log Type

- **SUCCESS**: The command achieved its primary goal. Use after deployments, provisioning, or any command that completes a user-requested action.
- **ERROR**: The command failed and cannot continue. Always include the reason and, when possible, a suggested fix. Only use for top-level command failures, not internal retries.
- **WARNING**: The command succeeded (or will proceed), but something unexpected happened that the user should know about. Examples: deprecated flags, region capacity concerns, overwriting existing resources.

#### Log Format

```
Provisioning Azure resources (azd provision)
PREFIX: Message goes here.
```

(✓) Done: Creating App Service Plan: plan-r2w2adrz3rvwxu
(✓) Done: Creating Log Analytics workspace: log-r2w2adrz3rvwxu
(✗) Failed: Creating Cosmos DB: cosmos-r2w2adrz3rvwxu

The '{US} West US 2 (westus)' region is currently experiencing high demand
and cannot fulfill your request. Failed to create Cosmos DB account.
#### Log Types

**Success logs** — Use `WithSuccessFormat` (green/bright green).

ERROR: Unable to complete provisioning of Azure resources, 'azd up' failed
```
SUCCESS: Message goes here.
```

**Skipped scenario:**
**Error logs** — Use `WithErrorFormat` (red/bright red). Follow a `[Reason] [Outcome]` structure when possible.

```
Note: Steps were skipped because _____ (directory, or specified service name)
If you want to deploy all services, you can run azd deploy --all or
move to root directory.
ERROR: Message goes here.
```

(✓) Done: [Verb] Message goes here
(✓) Done: [Verb] Message goes here
(-) Skipped: [Verb] Message goes here
**Warning logs** — Use `WithWarningFormat` (yellow/bright yellow).

```
WARNING: Message goes here.
```

### Command Output Standards
#### In-Context Example

**Error with suggested command** (shows multi-line composition with inline highlights):

```
ERROR: 'todo-mongojs' is misspelled or missing a recognized flag.
Run azd up --help to see all available flags.
```

> Colors: `ERROR:` line → `WithErrorFormat`. `azd up --help` → `WithHighLightFormat`.

### User Inputs

Certain azd commands require the user to input text, select yes/no, or select an item from a list. Examples include:

- Inputting an environment name (text input)
- Initializing a new Git repository (y/n)
- Selecting a location to deploy to (list select)

#### General Guidelines

All input requests are in bold and begin with a blue `?`. This helps ensure that they stand out to users as different from other plain text logs and CLI outputs.

#### Text Input

Text input captures a single line of input from the user.

**Initial state:**

The prompt is displayed with a `[Type ? for hint]` helper in **hi-blue bold text** via `WithHighLightFormat` (Bright Blue, ANSI 94), followed by ghost-text (secondary text color) as placeholder content.

```
? This captures a single line of input: [Type ? for hint]
```

> Colors: `?` → `WithHighLightFormat` + `WithBold`. `[Type ? for hint]` → `WithHighLightFormat` + `WithBold`.

**Hint feature:**

- **Structured output**: Support `--output json` for machine-readable output
- **Progress indicators**: Use spinners and progress bars for long operations
- **Colorization**: Use consistent colors (green=success, red=error, yellow=warning)
- **URLs**: Always include relevant portal/console URLs for created resources
If the user types `?`, a hint line appears below the prompt to provide additional guidance.

```
? This captures a single line of input: [Type ? for hint]
Hint: This is a help message
```

> Colors: `?` and `[Type ? for hint]` → `WithHighLightFormat` + `WithBold`.

#### Yes or No Input

- Yes/no inputs include a `(Y/n)` delineator at the end of the input request (before the colon).
- Users can either input `y`/`n` or hit the return key which will select the capitalized choice in the `(Y/n)` delineator.

```
? Do you want to initialize a new Git repository in this directory? (Y/n):
```

> Colors: `?` → `WithHighLightFormat` + `WithBold`.

#### List Select

The list select pattern presents a list of options for the user to choose from.

**Initial state:**

The prompt is displayed with a `Filter:` line showing ghost-text ("Type to filter list") and a footer hint in **hi-blue text** via `WithHighLightFormat` (Bright Blue, ANSI 94). The active selection is indicated by `>` and displayed in bold blue text.

```
? Select a single option: [Use arrows to move, type to filter]

> Option 1
Option 2
Option 3
Option 4
Option 5
Option 6
...
```

> Colors: `?` → `WithHighLightFormat` + `WithBold`. `[Use arrows to move, type to filter]` → `WithHighLightFormat` + `WithBold`. `> Option 1` (selected item) → `WithHighLightFormat` + `WithBold`.

**Display rules:**

- The list should display no more than 7 items at a time.
- When a list contains more than 7 items, ellipses (`...`) should be used to help users understand there are more items available up or down the list.
- If possible, the most commonly selected item (or the item we want to guide the user into selecting) should be highlighted by default.
- The active selection in the list should be bold and in blue text, prefixed with `>`.

**Hint:**

- The `[Type ? for hint]` pattern follows the same behavior as Text Input — **hi-blue bold** via `WithHighLightFormat` (Bright Blue, ANSI 94).

**After submitting:**

Once the user makes their selection:

- The input changes from primary text to hi-blue text
- The `[Type ? for hint]` helper disappears
- If the hint line was visible, it also disappears
- The list collapses and the selected value is printed in blue text next to the prompt

```
? Select an Azure location to use: (US) East US 2 (eastus2)
```

> Colors: `?` → `WithHighLightFormat` + `WithBold`. `(US) East US 2 (eastus2)` (selected value) → `WithHighLightFormat`.

### CLI Color Standards

Expand All @@ -173,7 +310,6 @@ Use these functions for consistent color formatting across the CLI:
| **Warning** | `WithWarningFormat(text string)` | Warning messages, non-critical issues |
| **Error** | `WithErrorFormat(text string)` | Error messages, failures |
| **Gray text** | `WithGrayFormat(text string)` | Secondary information, muted text |
| **Hint text** | `WithHintFormat(text string)` | Helpful suggestions, tips |
| **Bold text** | `WithBold(text string)` | Emphasis, headers |
| **Underline** | `WithUnderline(text string)` | Emphasis (use sparingly) |

Expand All @@ -187,7 +323,7 @@ fmt.Println(output.WithSuccessFormat("(✓) Done:") + " Creating resource")
fmt.Println(output.WithWarningFormat("(!) Warning:") + " Configuration may need update")

// Error message
fmt.Println(output.WithErrorFormat("() Failed:") + " Unable to connect")
fmt.Println(output.WithErrorFormat("(x) Failed:") + " Unable to connect")

// Hyperlink
fmt.Printf("View in portal: %s\n", output.WithLinkFormat(url))
Expand All @@ -204,6 +340,16 @@ fmt.Printf("Run %s to deploy\n", output.WithHighLightFormat("azd deploy"))
- **Theme support**: Test in both light and dark terminal themes
- **Fallback**: Ensure output remains readable if colors are disabled

#### Common Mistakes

| ❌ Don't | ✅ Do | Why |
| --- | --- | --- |
| `Error: something went wrong` | `ERROR: something went wrong.` | All-caps prefix is required |
| `Done: Created resource` | `(✓) Done: Created resource` | Include icon prefix for progress states |
| `color.Red("ERROR")` | `output.WithErrorFormat("ERROR:")` | Always use helper functions |
| Print bare success text | `SUCCESS: Your app has been deployed!` | Always include the `SUCCESS:` prefix |
| `(✗) Failed:` (Unicode ballot X) | `(x) Failed:` (lowercase letter x) | Match the codebase symbol |

<details>
<summary>📚 Learn more about ANSI color codes (optional reference)</summary>

Expand Down Expand Up @@ -252,6 +398,36 @@ Note: There is a discrepancy in the naming convention between ANSI Color coding

</details>

### Loading Animation (Progress Spinner)

`azd` uses a **bar-fill spinner** to indicate ongoing operations. The animation displays a pair of `|` border characters with `=` fill characters that bounce back and forth, alongside a status message describing the current operation.

#### Animation Behavior

The spinner **animates in place** on a single line by overwriting itself. The `=` fill characters grow and bounce back and forth between the `|` borders, creating a fluid loading effect:

```
|===== | Creating App Service: my-app-r2w2adrz3rvwxu
```

The full animation cycle frames are:

```
| | → |= | → |== | → |=== | → |==== | → |===== | → |====== | → |=======|
|=======| → | ======| → | =====| → | ====| → | ===| → | ==| → | =| → | |
```

These frames repeat continuously on the **same line** until the operation completes. The spinner bar is displayed in **gray text** via `WithGrayFormat` to keep focus on the status message.

#### Implementation

Use `console.ShowSpinner()` and `console.StopSpinner()` from [`pkg/input/console.go`](../../pkg/input/console.go) to display the bar-fill spinner. These are the standard functions used across all azd commands.

```go
// Start or update spinner
console.ShowSpinner(ctx, "Creating App Service: my-app-r2w2adrz3rvwxu", input.Step)
```

## Testing Standards

### Test Structure
Expand Down
Loading