Azure / Azure/azure-functions-core-tools

Design: Workload coordination model and CLI/workload alignment

Open
#5,413 0 comments 0 reactions 0 assignees View on GitHub
area: build/release design v5
Dominant language
C#
Stars
1.5k
Forks
498
Avg merge
5d 4h
Merged PRs (30d)
15

Description

## Context

This was originally part of the [CLI release design](https://github.com/Azure/azure-functions-core-tools/pull/5391) (Decisions 3 + 4) but was determined in design review to be a separate concern from the release story. Captured here so the thinking is not lost.

---

## Coordination model and workload alignment

This is the core of the design: how a fleet of independently versioned, cross-repo workloads stays aligned with a single CLI users can reason about.

### How alignment actually works (no CLI-shipped manifest)

Keep the CLI a thin anchor: resolve compatibility through per-workload metadata and profiles, not a CLI-shipped manifest or bill of materials. Workloads are acquired on demand by the user, never auto-installed silently by the CLI:

- `func workload install ` resolves the **latest compatible stable** version from the catalog (NuGet) by default. `func workload update` moves an installed workload to the latest compatible version. An explicit `--version` overrides.
- `func setup --feature <...>` orchestrates those installs for a ready machine, and `func start --profile ` selects the host version to run.

Today the host/workload boundary is **defined but not version-gated**. Workloads bind to the CLI's single shipped copy of the contract assemblies (`Azure.Functions.Cli.Abstractions`, the DI abstractions, and transitionally `System.CommandLine`); `WorkloadLoadContext` delegates exactly those back to the CLI's load context, and the .NET runtime's load rules handle target-framework compatibility. What is not in place is any version-compatibility check. The "workload too old, run `func workload update`" behavior described in workload-spec §10.2 is specified but not yet implemented (the install, resolve, and load paths reject only on bad schema and path-escape, never on version). So the CLI currently loads whatever workload it is given and only fails at runtime if the contract genuinely mismatches.

### The concern: incompatibility is ungated, especially forward

With no version check, a mismatched workload and CLI is caught only at runtime, if at all. The sharp edge is the forward direction: when a new capability is added to the shared CLI base contract (the `Azure.Functions.Cli.Abstractions` package the CLI and workloads compile against), a newer workload that uses it needs a newer CLI. Nothing today lets that workload declare "I require `func >= X`", so an older CLI installs it and fails at load with no clear reason. The reverse direction (an old workload on a newer CLI) is equally ungated.

### Proposal: a minimum CLI version, stamped by the Workload SDK

Introduce a declared **minimum CLI (contract) version** per workload, enforced by the resolver and loader. Three parts:

1. **Declaration (where the Workload SDK helps).** The workload states the minimum CLI / contract version it needs. The exact form is an open question in the workload specs (workload-package-layout §6 and §11): a `workload.json` field, a reserved tag such as `func-cli-min:5.2`, or a NuGet `` range on the contract package (which §9.3 discourages). The planned **Func Workload SDK** (`Azure.Functions.Cli.Workload.Sdk`) is the natural place to derive and stamp this automatically from the `Abstractions` version the workload built against, so authors do not hand-author it. The SDK is build-time only: it makes the declaration accurate but cannot enforce anything on a user's machine.

2. **Enforcement with a clear upgrade path.** `func workload install` / `update` resolves the newest version whose minimum CLI is satisfied by the running CLI. When a newer version exists but needs a newer CLI, the CLI installs the newest compatible version and tells the user that a newer one requires `func >= X` (for example, run `func update`), instead of failing opaquely. This is the runtime half the SDK cannot provide, and the counterpart to the (today unimplemented) "workload too old" path.

3. **Release coordination.** The CLI that carries the new contract capability must reach the distribution channels **before or together with** the workload that depends on it, so users have an upgrade path the moment that workload ships, and the workload's release notes must state the minimum `func` version. Because `Azure.Functions.Cli.Abstractions` is itself a separately released, versioned package (its own pipeline on `vnext`), a base-contract change is sequenced as: abstractions release, then a CLI release that ships it, then the dependent workload.

### What "v5.x" means

Just the CLI version. Workloads and profiles version independently and can even republish without a `func` release. The CLI is the thin, stable anchor; everything else is acquired and resolved against it.

### CLI-anchored release coordination

A v5 release is **anchored by the CLI release event**: the GitHub Release (signed, versioned CLI binaries) and the installer land together as the single source of truth for what shipped. Sequencing:

1. Owner repos publish the workload versions they want available to NuGet, ahead of time. Workloads are continuously available; they do not wait for the CLI.
2. The CLI release builds and signs the CLI binaries and publishes the GitHub Release. This is the anchored moment the release "exists". Updated built-in profiles (if any) publish through their own pipeline (#5329).
3. Package-manager channels fan out from that GitHub Release: automated and same-day where we control the channel (npm, Homebrew, winget, apt), best-effort where submission is gated by a third party.

### Implications

- The minimum-CLI proposal needs a committed declaration form (ideally SDK-stamped) and defined resolver behavior before GA. Until then, forward and reverse incompatibility is a known, ungated gap.
- Built-in profiles must be published and updated in step with host/bundle releases so a fresh `func setup` / `func start --profile` yields a tested, cloud-aligned combination. Owned by #5329 and #5332.
- We need a cross-repo release-readiness checklist (the workloads a release depends on are published, smoke-tested, and declare correct CLI-compatibility windows before the CLI release goes out) and aggregated release notes that pull each workload's notes into the CLI release notes.

### Open questions

- Do we need to have a manifest or a min CLI version declared for workloads?
- Workload minimum-CLI declaration: NuGet dependency on `Azure.Functions.Cli.Abstractions` vs a `func-cli-min` metadata field, plus the resolver message when a newer workload needs a newer CLI (carried from workload-package-layout §6/§11).
- Confirm whether partner tooling still needs the internal tooling feed for v5.

Contributor guide

Open the contributing guide

Research direction

Start with the workload-spec §10.2 and workload-package-layout §§6 and 11 referenced in the issue, then review the CLI release design in PR #5391 and related profile work in #5329 and #5332. The work is not ready for a focused code change: first resolve the declaration format, resolver and loader behavior, and release-readiness sequence, with an implementation plan that defines how compatibility and upgrade guidance are verified.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, cli, csharp
Domain
cli, devops, release
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.