Skip to main content

agent-framework-py-release

Use when cutting a Python release for the microsoft/agent-framework monorepo. Triggers on "bump py versions", "cut a python release", "prepare release PR for python", "release py packages", "bump python to X.Y.Z", or similar requests to bump Python package versions and prepare a release PR. Handles all four lifecycle tiers (alpha, beta, rc, released) with CHANGELOG-driven selective bumps, floor bound checks, and post-bump validation.

Source facts

Repository
microsoft/agent-framework
Last source activity
October 2, 2026 at 11:31
Detected SKILL.md language
English
Stars
13,948
Forks
2,427

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
agent-framework-py-release
description
Use when cutting a Python release for the microsoft/agent-framework monorepo. Triggers on "bump py versions", "cut a python release", "prepare release PR for python", "release py packages", "bump python to X.Y.Z", or similar requests to bump Python package versions and prepare a release PR. Handles all four lifecycle tiers (alpha, beta, rc, released) with CHANGELOG-driven selective bumps, floor bound checks, and post-bump validation.
# Agent Framework Python Release Cuts a Python release PR for the `microsoft/agent-framework` monorepo. ## Core principle: CHANGELOG drives bumps **No more universal lockstep.** A package only bumps if it has a CHANGELOG entry this cycle. Draft the CHANGELOG first, then derive the bump list from it. Exceptions to selective bumping (these stay coupled regardless of per-package changes): - **Root `agent-framework` is coupled to `agent-framework-core` via `agent-framework-core[all]==X.Y.Z`** (exact pin in `python/pyproject.toml`). If `core` bumps, root bumps. Root may also bump independently for its own changes (docs/metadata/extras). - **Beta-tier cohort bumps are still allowed** when the user explicitly wants a fresh date stamp across all betas for cohort signaling — but this is a deliberate user decision per release, not a default. If the user explicitly states which packages to bump (or hands over a PR list per package), treat that as authoritative. ## Lifecycle tiers and version rules Use `python/.github/skills/python-package-management/SKILL.md` as the source of truth for lifecycle version patterns, date-stamp cutoffs, classifier alignment, and internal dependency updates. For release work, derive the live tier map at release time from `python/PACKAGE_STATUS.md` and the actual `version =` lines in each `pyproject.toml`. Do not hardcode counts — packages move between tiers. ## Inputs to confirm before bumping 1. **The changeset**: explicit commits/PRs the release covers, OR derive from `git log ${LAST_RELEASED_TAG}..${RELEASE_BASE} -- python/`. 2. **Per-package CHANGELOG entries**: which packages will get a line in the new release section. This list IS the bump list. 3. **Per-released-package semver bump**: for each released-tier package that has a CHANGELOG entry, decide PATCH / MINOR / MAJOR. 4. **Date stamp** (only if any alpha/beta is being bumped): default from the `python-package-management` date-stamp rule. 5. **Optional cohort bump?**: ask if betas should all get a new date stamp regardless of per-package changes. Default: no. If the user states target versions or a date explicitly, use exactly what they said — do not "correct" based on historical timezones. ## Non-negotiable rules - **Release workflow owns the CHANGELOG**: individual feature/fix PRs do not edit `python/CHANGELOG.md`; this workflow creates the entries centrally from merged changes. - **CHANGELOG-driven bumps**: only packages mentioned in the new CHANGELOG section get version bumps. Exceptions: root follows core (==pin); user-opted cohort bump on betas. - **Follow `python-package-management` for package lifecycle and versioning rules** — do not duplicate those rules in this release workflow. - **No `Co-Authored-By` trailer** on any commit. - **Use `uv run`** for all Python/poe commands (`uv run poe ...`, `uv run pytest ...`). - **Never rename an existing CHANGELOG section header** during a new release cut. Only INSERT a new section above existing ones. - **Footer reference links are part of the CHANGELOG edit**, not optional. ## Workflow ### 1. Orient and create branch ```bash git fetch origin main --tags --quiet git fetch upstream main --tags --quiet 2>/dev/null || true git status # Fork clones use upstream/main as the authoritative release base; direct clones use origin/main. if git show-ref --verify --quiet refs/remotes/upstream/main; then RELEASE_BASE=upstream/main else RELEASE_BASE=origin/main fi git log -1 --oneline "$RELEASE_BASE" ``` If the user already has a `bump-py-ver-release-*` branch checked out, use it. Otherwise: ```bash git checkout -b bump-py-ver-release-YYMMDD "$RELEASE_BASE" ``` ### 2. Build the live tier map Read `python/PACKAGE_STATUS.md` to enumerate current packages and lifecycle stages, and `grep '^version' python/pyproject.toml python/packages/*/pyproject.toml` to confirm actual versions. Cross-reference — if `PACKAGE_STATUS.md` shows a package as `beta` but its version looks like `1.0.0aYYMMDD`, surface the inconsistency before proceeding. Watch for: new packages added since the last release, lifecycle transitions (alpha→beta, beta→rc, rc→released), and stale packages that haven't been touched in many cycles. ### 3. Identify changeset Use the LATEST released tag as the compare base: ```bash LAST_RELEASED_TAG=$( git tag -l 'python-[0-9]*.[0-9]*.[0-9]*' \ | uv run --directory python python -c 'import sys; tags=[t.strip() for t in sys.stdin if t.strip()]; print(max(tags, key=lambda t: tuple(map(int, t[7:].split(".")))))' ) echo "Compare base: $LAST_RELEASED_TAG" ``` List commits and packages touched: ```bash git log --oneline ${LAST_RELEASED_TAG}..${RELEASE_BASE} -- python/ ':!python/CHANGELOG.md' # Per-commit package footprint for sha in $(git log --format='%H' ${LAST_RELEASED_TAG}..${RELEASE_BASE} -- python/); do echo "--- $(git show -s --format='%h %s' $sha) ---" git show --name-only --format='' $sha | grep '^python/packages/' | \ sed 's|^python/packages/||' | awk -F/ '{print $1}' | sort -u done ``` When both remotes exist, record whether the fork is behind the authoritative base: ```bash git rev-list --left-right --count origin/main...upstream/main ``` If user provides an explicit commit/PR list, treat THAT as authoritative. #### 3a. Build the authoritative touched-package set Aggregate the per-commit footprint into a single union across the whole range. This is the **source of truth** for what must appear in the CHANGELOG. Save it before drafting entries. ```bash # Union of all touched package directories across the range git log --name-only --format='' ${LAST_RELEASED_TAG}..${RELEASE_BASE} -- python/packages/ \ | grep '^python/packages/' \ | sed 's|^python/packages/||' \ | awk -F/ '{print $1}' \ | sort -u # Root-level files (drive a root agent-framework entry if substantive) git log --name-only --format='' ${LAST_RELEASED_TAG}..${RELEASE_BASE} \ -- python/pyproject.toml python/agent_framework_meta/ python/README.md \ 2>/dev/null | grep -v '^$' | sort -u ``` **What "touched" means for bump purposes** (apply judgment, document in commit message): | Change scope under `python/packages/<pkg>/` | Drives a bump? | | --- | --- | | Source code under `<pkg>/agent_framework_*` or the package's library tree | **Yes** — ship-affecting | | `pyproject.toml` (deps, classifiers, extras, version metadata) | **Yes** — publishes new metadata | | `README.md` substantive changes (env vars, install instructions, usage) | **Yes** — user-facing | | `README.md` typo/wording-only | Judgment — usually no, but record under `### Changed` if you do bump | | Tests only (`tests/`) | Usually no — test changes don't ship to PyPI consumers. Bump only if the test change reflects a real behavior change in the package | | Package-local samples (alpha packages only, before promotion) | **Yes** for alpha; samples ship with the alpha package | | Repo infra touching the package dir (CI config, lint config) | No — record under `- **tests**:`, `- **samples**:`, or `- **docs**:` instead | Root `agent-framework` is touched when `python/pyproject.toml`, `python/agent_framework_meta/`, or root `README.md` substantive content changed. ### 4. Draft CHANGELOG entries (THIS DRIVES THE BUMP LIST) Individual feature/fix PRs intentionally do not add CHANGELOG entries. During release preparation, derive this section centrally from the merged PRs since the last released tag. Locate `## [Unreleased]` and the top existing release header. INSERT a new section between them. **New section structure:** ```markdown ## [<release-label>] - YYYY-MM-DD ### Added - **agent-framework-<pkg>**: <subject> ([#NNNN](https://github.com/microsoft/agent-framework/pull/NNNN)) ### Changed - **agent-framework-<pkg>**: ... ### Fixed - **agent-framework-<pkg>**: ... ``` `<release-label>` is the released-tier target if any released package is bumping (e.g. `1.7.0`), or the date stamp (e.g. `1.0.0b260528`) if the release is prerelease-only. Reflect the user's framing. **Categorization heuristics (read commit subject + PR title/body):** - **Added**: new public APIs, new packages, new samples, `feat(...)`, new re-exports from `agent_framework`, new capabilities surfaced from underlying SDKs - **Changed**: metadata/classifier corrections, dependency upgrades, test infra changes, signature adjustments on existing APIs, renames, doc updates, lifecycle transitions - **Fixed**: `fix(...)`, bug/crash/regression repairs, noise reduction (e.g. stop emitting spurious warnings), protocol-compliance fixes - **Removed**: deprecations/deletions (use `[BREAKING]` prefix if breaking) **Entry format:** - `- **agent-framework-<pkg>**: <subject, grammar-normalized> ([#NNNN](https://github.com/microsoft/agent-framework/pull/NNNN))` - Multiple packages touched by one PR: comma-separated bold names at the head: `- **agent-framework-core**, **agent-framework-foundry**: ...` - Root package changes: use `- **agent-framework**: ...` - Test/sample/repo infra: `- **tests**: ...`, `- **samples**: ...`, `- **docs**: ...` (these do not drive package bumps) **Once entries are drafted, the set of `**agent-framework-<pkg>**` and root `**agent-framework**` mentions IS the bump list.** Anything not mentioned does not bump. #### 4a. Reconcile mentions against the touched-package set (DO NOT SKIP) Before moving on, prove that every ship-affecting touched package has at least one CHANGELOG entry. A package whose code changed but is missing from CHANGELOG will NOT bump — and the fix will not ship to PyPI consumers. ```bash # 1. Touched ship-affecting packages and root package files (from step 3a) TOUCHED_PACKAGES=$(git log --name-only --format='' ${LAST_RELEASED_TAG}..${RELEASE_BASE} -- python/packages/ \ | grep '^python/packages/' \ | sed 's|^python/packages/||' \ | awk -F/ '{print $1}' \ | sort -u) ROOT_TOUCHED=$(git log --name-only --format='' ${LAST_RELEASED_TAG}..${RELEASE_BASE} \ -- python/pyproject.toml python/agent_framework_meta/ python/README.md \ 2>/dev/null | grep -v '^$' | sort -u) TOUCHED=$( { if [ -n "$TOUCHED_PACKAGES" ]; then echo "$TOUCHED_PACKAGES"; fi if [ -n "$ROOT_TOUCHED" ]; then echo "agent-framework"; fi } | sort -u ) # 2. Packages mentioned in the new CHANGELOG section # (Extract from the section you just drafted — adjust the awk range to the new section's bounds) MENTIONED=$(awk ' /^## \[<release-label>\]/ { in_section=1; next } in_section && /^## \[/ { exit } in_section { print } ' python/CHANGELOG.md \ | grep -oE '\*\*agent-framework(-[a-z0-9_-]+)?\*\*' \ | sed 's/\*\*//g;s/^agent-framework-//' \ | sort -u) # 3. Diff — anything in TOUCHED but missing from MENTIONED is a gap comm -23 <(echo "$TOUCHED") <(echo "$MENTIONED") ``` For every gap, decide explicitly with the user: - **Add a CHANGELOG entry and bump** — the default. Even small package changes (a dep upgrade, a metadata fix) deserve an entry under `### Changed`. - **Intentionally skip** — only when the touched files are demonstrably non-shipping (e.g. comments-only, test infra). Note the skip in the commit message body so reviewers see the reasoning. Package-name aliasing to watch for: directory `foundry_local` → package `agent-framework-foundry-local`; `github_copilot` → `agent-framework-github-copilot`; `azure-ai-search` → `agent-framework-azure-ai-search`. The directory name and the published PyPI name are not always identical — confirm both when reconciling. **Footer reference links** (REQUIRED every release): ```bash grep -n "^\[.*\]:" python/CHANGELOG.md | head -5 ``` Two edits when a released-tier bump is in play: 1. Advance `[Unreleased]` compare base from `python-${OLD_RELEASED}...HEAD` to `python-${NEW_RELEASED}...HEAD`. 2. INSERT a new `[${NEW_RELEASED}]` line ABOVE the previous version's link: `[${NEW_RELEASED}]: https://github.com/microsoft/agent-framework/compare/python-${OLD_RELEASED}...python-${NEW_RELEASED}` For prerelease-only releases (no released-tier bump this cycle), footer links don't change. ### 5. Apply bumps per tier For each package in the bump list, choose the rule for its current tier. Use anchored `sed` (`^version = "..."$`) so only the project's own version matches. Use `sed -i.bak` plus backup cleanup for portable in-place edits across macOS/BSD sed and GNU sed. **Released tier (per-package semver):** ```bash # Example: openai goes 1.6.0 -> 1.6.1 (PATCH); core stays sed -i.bak 's/^version = "1.6.0"$/version = "1.6.1"/' python/packages/openai/pyproject.toml rm python/packages/openai/pyproject.toml.bak
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub