[EPIC] Auto-updates and daily channel
- Dominant language
- Go
- Stars
- 569
- Forks
- 364
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 136
Description
## Problem statement
We want to make it even easier to stay current and get early access to new features. The core `azd update` command and daily channel are now shipping, and now we want to expand the safety net by allowing teams pin to a known-good version. We also want a one-command rollback. This epic tracks completing those guarantees so auto-update is accessible for everyone from solo developers to platform teams managing `azd` across their organization.
## Vision
Two channels, one command, zero surprises. The foundation is live: **Daily** gives early adopters bleeding-edge features, **Stable** gets reliable releases, and `azd update` ties it all together with opt-in auto-update. The remaining work is about making auto-update *bulletproof*—crash-loop guards, version pinning, and instant rollback—so developers always have control and can always recover.
## Who this helps
- **Early adopters and power users** who want the newest features as soon as they're testable. The daily channel gives them early access and a direct way to influence the product direction, with a clear opt-in/opt-out path.
- **Platform engineers** managing `azd` across teams or organizations. Version pinning, rollback capability, and safety guards give them confidence that updates are controlled and predictable—especially in CI/CD pipelines.
- **Azure developers** who just want things to work. A gentle nudge when a new version is available and a one-command upgrade path means staying current is effortless.
- **Contributors and maintainers** who benefit from a pre-release feedback channel that surfaces issues early, improving quality for everyone before features reach stable.
## What already ships
The following capabilities are **implemented and merged** (PR [#6942](https://github.com/Azure/azure-dev/pull/6942) + follow-ups [#7011](https://github.com/Azure/azure-dev/pull/7011), [#7012](https://github.com/Azure/azure-dev/pull/7012)):
| Capability | Details |
|---|---|
| **`azd update` command** | Manual check-and-install for the active channel. Works on Windows (MSI + script), macOS (Homebrew + binary), Linux (script + binary). Blocks in CI/CD environments. |
| **Channel model** | Two channels: `stable` and `daily`. Channel inferred from binary version string (contains `daily.` → daily channel). Explicit set via `azd update --channel stable\|daily`. |
| **Channel switching** | Confirmation prompt on switch. Warns when switching to daily via package manager (requires uninstall-first workflow for Homebrew/winget). Channel persisted in `azd config` (`updates.channel`). |
| **Opt-in auto-update** | Enable with `azd config set updates.autoUpdate on`. Stages new binary in background; applies on next `azd` invocation via `ApplyStagedUpdate()`. Configurable check interval (`--check-interval-hours`, default 24h stable / 4h daily). |
| **Staged update pipeline** | `StageUpdate` → `HasStagedUpdate` → `ApplyStagedUpdate` → `CleanStagedUpdate`. Staged binary validated (`verifyStagedBinary`) before apply. Applied-marker tracking for post-update messaging. |
| **Code signature verification** | macOS: `codesign --verify`. Windows: Authenticode signature check. Unsigned daily builds allowed with log warning. |
| **MSI update backup** | On Windows MSI path: `backupCurrentExe()` creates temp backup before replace. `restoreExeFromBackup()` on failure. Backup cleaned up after success. |
| **Package manager awareness** | Detects Homebrew, winget, apt, snap installs. Routes updates through native package manager or warns when channel switch requires uninstall. |
| **Update cache** | Version check results cached to `update-check.json` with channel-aware expiration. Manual `azd update` forces fresh check (`ignoreCache: true`). |
| **First-use notice** | Beta feature stage notice on first `azd update` invocation with link to feature stages documentation. |
**Config keys in use**: `updates.channel`, `updates.autoUpdate`, `updates.checkIntervalHours`
**Key source files**: `cli/azd/cmd/update.go`, `cli/azd/pkg/update/manager.go`, `cli/azd/pkg/update/config.go`, `cli/azd/pkg/update/msi_windows.go`
## Goals — remaining work (in scope)
### 1. Crash-loop guard ([#6983](https://github.com/Azure/azure-dev/issues/6983))
**Problem**: If a staged auto-update produces a binary that panics on startup, the user is stuck. There's no `AZD_SKIP_AUTO_UPDATE` escape hatch, no failure counter, and no automatic rollback.
**Proposed behavior**:
- **`AZD_SKIP_AUTO_UPDATE=1` env var**: Bypasses `ApplyStagedUpdate()` entirely. Escape hatch for emergencies and debugging.
- **Consecutive-failure counter**: Track apply attempts in a local state file (e.g., `~/.azd/update-apply-attempts.json`). Increment on each `ApplyStagedUpdate()` call; reset to zero on successful `azd` startup (i.e., command runs to completion or interactive session starts).
- **Auto-disable threshold**: After **3** consecutive failed apply attempts, auto-update is disabled and the staged binary is deleted. A warning is printed: `"Auto-update disabled after 3 consecutive failures. Run 'azd update' to retry manually."`
- **"Last good version" marker**: Write the current working version to `~/.azd/last-good-version` on every successful startup. This gives the rollback command (below) a known-safe target.
**Open design questions**:
- Should the failure counter be time-windowed (e.g., 3 crashes within 1 hour) or purely sequential?
- Should the auto-disable be sticky (require `azd config set updates.autoUpdate on` to re-enable) or auto-reset after a successful manual `azd update`?
### 2. Version pinning ([#6984](https://github.com/Azure/azure-dev/issues/6984))
**Problem**: Teams need reproducible builds. Today `azd update` always pulls "latest" for the channel. There's no way to pin a specific version, and auto-update ignores team constraints.
**Proposed behavior**:
- **`azd update --version X.Y.Z`**: Install a specific version, regardless of channel. The version must exist in the release feed for the active channel.
- **Global pin via config**: `azd config set updates.pinnedVersion 1.23.5`. When set:
- `azd update` skips the update if current version matches the pin
- Auto-update (`ApplyStagedUpdate`) refuses to apply if the staged version differs from the pin
- `azd update --version` overrides the pin for that invocation but doesn't clear it
- **Project-level pin via `.azd-version` file**: A file in the project root (next to `azure.yaml`) containing a single semver string. When present:
- `azd` prints a warning on startup if the running version doesn't match
- Auto-update respects the project pin (won't apply a staged version that doesn't match)
- Project pin takes precedence over global pin
- **Pin interaction with channels**: Pinned version must match the active channel. Pinning a stable version while on the daily channel (or vice versa) produces an error with a clear suggestion.
**Open design questions**:
- Should `.azd-version` support ranges (e.g., `>=1.23.0 <2.0.0`) or only exact versions?
- Should `azd update --version` for daily builds accept build numbers (e.g., `daily.12345`) in addition to semver?
### 3. Rollback / recovery ([#6982](https://github.com/Azure/azure-dev/issues/6982))
**Problem**: Today the MSI path backs up the binary temporarily during update, but the backup is deleted after success. If a user realizes the new version has a problem *after* a successful update, there's no way to go back without a full reinstall.
**Proposed behavior**:
- **Persistent backup**: After a successful update (manual or auto), keep the previous binary as `azd.prev` (or in `~/.azd/backup/azd-`). Only the most recent previous version is retained.
- **`azd update --rollback`**: Replace the current binary with the backup. Print the version being restored. Clear any staged update. Reset the crash-loop counter.
- **Rollback with no backup**: If no backup exists (e.g., fresh install), print a clear error: `"No previous version available. Use 'azd update --version X.Y.Z' to install a specific version."`
- **Interaction with version pinning**: Rollback should set `updates.pinnedVersion` to the restored version to prevent auto-update from immediately re-applying the problematic version. The user can clear the pin with `azd config unset updates.pinnedVersion` when ready.
**Open design questions**:
- Should rollback keep N previous versions (like a version stack) or just the most recent?
- Should the backup include the version metadata so `azd update --rollback` can report "Rolled back from X.Y.Z to A.B.C"?
## Non-goals (out of scope)
- **Forced auto-updates**: Updates are always opt-in. No silent upgrades, no "update required to continue" gates.
- **Managing updates for non-azd tools**: That's `azd tool`'s job. This epic covers azd itself.
- **Daily channel SLA**: Daily builds prioritize early access over stability. We'll address issues quickly, but daily channel users should expect occasional rough edges compared to stable.
- **Multi-version management**: Running multiple azd versions side-by-side (like `nvm` for Node) is out of scope.
## Success criteria
- [x] ~~Daily channel available with distinct branding and documentation on how to opt in~~ *(shipped)*
- [x] ~~`azd update` works on Windows, macOS, and Linux for manual updates~~ *(shipped)*
- [x] ~~Auto-update opt-in functional with configurable check frequency~~ *(shipped)*
- [x] ~~Channel switching works with confirmation and package-manager awareness~~ *(shipped)*
- [ ] Crash-loop guard: auto-update disables itself after 3 consecutive startup failures, and `AZD_SKIP_AUTO_UPDATE=1` bypasses staged apply
- [ ] Version pinning: `azd config set updates.pinnedVersion X.Y.Z` prevents auto-update past that version; `.azd-version` file provides project-level pinning
- [ ] `azd update --version X.Y.Z` installs a specific version
- [ ] Rollback: `azd update --rollback` restores the previous version without data loss
- [ ] Daily channel has completed at least one full pre-release cycle (ship → feedback → fix → stable)
## Dependencies
- **Azure Dev Tools (`azd tool`)**: Update mechanisms should feel cohesive. If `azd tool update` uses a different pattern than `azd update`, developers will be confused. Coordinate UX and implementation approach.
- **Release engineering**: Daily build pipeline is operational. Signing and distribution for both channels are in place.
- **Installer / package manager owners**: Homebrew, winget, apt, snap; package-manager-aware update routing is implemented. Additional changes may be needed for version pinning support (e.g., `brew pin`).
Contributor guide
Assessment
This issue has not been assessed yet.