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
6 changes: 4 additions & 2 deletions .github/workflows/release-assets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
# disagree; the artifact cannot exist if the invariant is broken.
run: python -m build
- name: Build the lifecycle bundle consumed by `ainative update`
# Protocol 3 by default since the Release V3 conversion: the bundle
# plus the external `ainative-release-v3.json` manifest that anchors it.
run: python scripts/build_lifecycle_bundle.py
- name: Every built artifact must carry the release version
# Filenames, wheel METADATA, sdist PKG-INFO and the protocol document
Expand All @@ -53,7 +55,7 @@ jobs:
V3_BRIDGE_RELEASE: ${{ vars.V3_BRIDGE_RELEASE }}
run: python scripts/check_release_gate.py --dist dist
- name: Write SHA256SUMS
run: cd dist && sha256sum *.whl *.tar.gz *.zip > SHA256SUMS && cat SHA256SUMS
run: cd dist && sha256sum *.whl *.tar.gz *.zip *.json > SHA256SUMS && cat SHA256SUMS
- name: Attest the build provenance of every artifact
# Standard, verifiable, automatable: GitHub attests that these bytes
# were produced by this workflow, in this repository, at this commit.
Expand All @@ -78,7 +80,7 @@ jobs:
--title "${GITHUB_REF_NAME}"
test "$(gh release view "${GITHUB_REF_NAME}" --json isDraft --jq .isDraft)" = "true"
gh release upload "${GITHUB_REF_NAME}" \
dist/*.whl dist/*.tar.gz dist/*.zip dist/SHA256SUMS
dist/*.whl dist/*.tar.gz dist/*.zip dist/*.json dist/SHA256SUMS
- name: Verify the uploaded assets, then publish the release
env:
GH_TOKEN: ${{ github.token }}
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Universal Engineering Rules
<!-- stack-version: 2.4.4 -->
<!-- stack-version: 2.5.0 -->
<!-- Cross-tool: Claude Code (@AGENTS.md in CLAUDE.md), Cursor (reads AGENTS.md natively at root + nested dirs), Codex (auto-loaded AGENTS.md) -->
<!-- Keep this file at the project root. Customize per project as needed. -->
<!-- Canonical source — reference this file (@AGENTS.md), do not copy it. Updates flow via `git pull` + /stack-upgrade. See UPDATING.md. -->
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [2.5.0] - 2026-09-17

Release Protocol V3: the official release publishes an external
`ainative-release-v3.json` manifest beside a protocol 3 lifecycle bundle
(`ainative-lifecycle-v3-2.5.0.zip`). The manifest's SHA-256 and size travel
as release-asset metadata (the external anchor), the runtime verifies them
before parsing anything, and the whole version chain is validated by
`scripts/check_release_versions.py --dist` before publication. The 2.4.4
bridge remains the documented path from older runtimes.

### Added

- **External release manifest and protocol 3 bundles**: `scripts/build_lifecycle_bundle.py` builds protocol 3 by default and emits `ainative-release-v3.json`; the release workflow publishes both, and the protocol-aware bridge gate blocks any V3 publication without a verifiable bridge (`V3_BRIDGE_RELEASE`).
- **Protocol-aware version gate**: `check_release_versions.py` detects the lifecycle protocol from the built artifacts and validates the manifest, the exact version chain and the anchored artifact bytes (a V2/V3 mix fails).

### Changed

- The lifecycle bundle default is protocol 3; `--protocol 2` remains for reproducing a bridge release.

## [2.4.4] - 2026-09-17

Multi-Forge v1: the first release carrying the generic-Git lifecycle, the
Expand Down
4 changes: 2 additions & 2 deletions README.fr.md
Original file line number Diff line number Diff line change
Expand Up @@ -614,11 +614,11 @@ OpenCode et Cursor), pose `AGENTS.md` et `conventions.json`.
# Relancez la ligne d'installation quand une release change le runtime du
# lifecycle ; `ainative update` vous le dira (CLI_UPDATE_REQUIRED).
#
# PyPI (ainative-dev-stack==2.4.4) est cable mais pas encore publie : il
# PyPI (ainative-dev-stack==2.5.0) est cable mais pas encore publie : il
# manque une configuration Trusted Publisher unique sur le compte PyPI
# (docs/RELEASING.md). D'ici la, la release GitHub epinglee ci-dessous est
# l'installation supportee.
pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.4.4" # release epinglee (reproductible)
pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.5.0" # release epinglee (reproductible)
cd /chemin/vers/votre-projet

ainative setup # guide : profil, integration machine, doctor
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,11 @@ manifest before parsing anything, and the support matrix is in `SUPPORT.md`.
# Re-run the install line when a release changes the lifecycle runtime;
# `ainative update` tells you when (CLI_UPDATE_REQUIRED).
#
# PyPI (ainative-dev-stack==2.4.4) is wired but not yet published: it needs
# PyPI (ainative-dev-stack==2.5.0) is wired but not yet published: it needs
# a one-time Trusted Publisher setup on the PyPI account (docs/RELEASING.md,
# "PyPI"), so until then the pinned GitHub release below is the supported
# install.
pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.4.4" # pinned release (reproducible)
pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.5.0" # pinned release (reproducible)
cd your-project

ainative setup # guided: profile, machine integration, doctor
Expand Down Expand Up @@ -664,7 +664,7 @@ cp tools/ai_docs/config.sh.example tools/ai_docs/config.sh
# Fill in Obsidian vault path, Python path, graphify binary

# 4. Install the CLI; it configures the hook — no hand-edited JSON:
pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.4.4"
pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.5.0"
ainative init --profile standard # merges ONE owned PostToolUse entry into .claude/settings.json
# (hand-registered before the lifecycle existed? init adopts it idempotently.)

Expand Down
2 changes: 1 addition & 1 deletion UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ update each project. `ainative update` refuses the other order with

```bash
# 1. the CLI / runtime
pip install --upgrade "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.4.4"
pip install --upgrade "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.5.0"

# 2. each project
ainative update check # is there anything newer? (works with any runtime)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.4.4
2.5.0
2 changes: 1 addition & 1 deletion ainative/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

from __future__ import annotations

__version__ = "2.4.4"
__version__ = "2.5.0"

__all__ = ["__version__"]
2 changes: 1 addition & 1 deletion ainative/lifecycle/release_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from .errors import LifecycleError
from .paths import validate_relative

MANIFEST_ASSET_NAME = "ainative-release-v3.json"
MANIFEST_ASSET_NAME = release_v3lib.MANIFEST_ASSET_NAME
MAX_MANIFEST_BYTES = 1 << 20 # 1 MiB of release manifest is already absurd
MAX_ARCHIVE_BYTES = 256 << 20 # 256 MiB — mirrors the V2 bound
MAX_ENUMERATION_ENTRIES = 30 # one API page; beyond it, incomplete
Expand Down
7 changes: 5 additions & 2 deletions ainative/lifecycle/release_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@

MANIFEST_SCHEMA = "ainative.release"
MANIFEST_PROTOCOL = "v3"
# The manifest is published under this exact release-asset name; the runtime
# finds it by it, and nothing else is ever treated as one.
MANIFEST_ASSET_NAME = "ainative-release-v3.json"
# The `lifecycle-protocol.json` a V3 bundle carries at its root; the V2 bundle
# keeps protocol 2 (provider.UPDATE_PROTOCOL_VERSION).
BUNDLE_PROTOCOL_VERSION = 3
Expand Down Expand Up @@ -408,6 +411,6 @@ def resolve_manifest(provider: ReleaseProvider, query: ReleaseQuery
"ReleaseManifest", "ReleaseProvider", "canonical_version", "select_candidate",
"verify_external_anchor", "parse_manifest", "lifecycle_bundle_name",
"require_exact_version_chain", "resolve_manifest", "fetch_manifest_for",
"MANIFEST_SCHEMA", "MANIFEST_PROTOCOL", "BUNDLE_PROTOCOL_VERSION",
"ARTIFACT_KIND_LIFECYCLE",
"MANIFEST_SCHEMA", "MANIFEST_PROTOCOL", "MANIFEST_ASSET_NAME",
"BUNDLE_PROTOCOL_VERSION", "ARTIFACT_KIND_LIFECYCLE",
]
2 changes: 1 addition & 1 deletion docs/MULTIVAULT-OPERATOR-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ history only. ENFORCED-DIAGNOSTIC and ENFORCED-AUTHENTICATED are not available.
1. Install and initialize the stack (pinned release; see README for the current version):

```powershell
pip install --upgrade "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.4.4"
pip install --upgrade "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.5.0"
ainative machine init # installs the method and assets for every harness
ainative machine doctor # healthy, or exit 1 naming the failing asset
```
Expand Down
4 changes: 2 additions & 2 deletions docs/PUBLIC-PILOT.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ source pilot-venv/bin/activate
# Windows (PowerShell):
pilot-venv\Scripts\Activate.ps1

pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.4.4"
pip install "git+https://github.com/Rwanbt/ai-native-dev-stack.git@v2.5.0"
ainative --version
```

The last command prints the lifecycle version, the state schema and the stack
version. **Pass:** it prints them without an error. Note the versions in the
feedback form.

PyPI (`pip install ainative-dev-stack==2.4.4`) is not published yet — the
PyPI (`pip install ainative-dev-stack==2.5.0`) is not published yet — the
one-time trusted-publisher setup on the PyPI account is still pending. The
pinned release above is the supported install for this pilot.

Expand Down
46 changes: 38 additions & 8 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ reminder; the gates fail closed and none of them fixes anything silently.

```bash
git checkout main && git pull --ff-only
git tag v2.4.4 <MAIN_SHA>
git push origin v2.4.4
git tag v2.5.0 <MAIN_SHA>
git push origin v2.5.0
```

The **Release assets** workflow then runs, in order:
Expand All @@ -47,6 +47,36 @@ The **Release assets** workflow then runs, in order:
A failure at any step leaves a draft release (or none) - never a visible
release with a partial asset set.

### V3 releases

Since the Release Protocol V3 conversion, the workflow builds a **protocol 3**
lifecycle bundle plus the external manifest, and the trust chain is:

```text
provider metadata (release assets)
↓
external manifest anchor: SHA-256 + size (GitHub asset metadata)
↓
ainative-release-v3.json
↓
lifecycle artifact: protocol 3, exact version, SHA-256, size
```

`check_release_versions.py --dist` validates the whole chain — manifest
version, `compatibility.runtime_version`, artifact version, artifact filename,
the anchored bytes and the bundle's own `lifecycle-protocol.json` — before
anything is uploaded, and the protocol-aware bridge gate proves the bridge a
V2 runtime needs. The documented upgrade path for an installed project is
explicit:

```text
old runtime → bridge release → upgrade the CLI → V3 update (`ainative update`)
```

A protocol 2 bridge release is still reproducible with
`python scripts/build_lifecycle_bundle.py --protocol 2`; its bundle is
`ainative-lifecycle-v2-<version>.zip` and no manifest is generated.

## V2 bridge gate (before the first V3 publication)

The first V3 release cannot be applied by any runtime older than V3, so every
Expand Down Expand Up @@ -100,29 +130,29 @@ workflow token, and GitHub does not let one workflow's token trigger another
exists, upload an already-published release with:

```bash
gh workflow run publish-pypi.yml -f tag=v2.4.4
gh workflow run publish-pypi.yml -f tag=v2.5.0
```

```bash
# what a user then runs
pip install ainative-dev-stack==2.4.4
pip install ainative-dev-stack==2.5.0
# or, isolated:
pipx install ainative-dev-stack==2.4.4
pipx install ainative-dev-stack==2.5.0
```

## Verifying what was published

```bash
# integrity: the bytes match the published sums
gh release download v2.4.4 --dir dist
gh release download v2.5.0 --dir dist
cd dist && sha256sum -c SHA256SUMS

# provenance: which workflow, repository and commit produced them
gh attestation verify dist/ainative_dev_stack-2.4.4-py3-none-any.whl -R Rwanbt/ai-native-dev-stack
gh attestation verify dist/ainative_dev_stack-2.5.0-py3-none-any.whl -R Rwanbt/ai-native-dev-stack

# PyPI provenance (attestations are published with the files)
python -m pip install --upgrade pypi-attestations
python -m pypi_attestations verify dist/ainative_dev_stack-2.4.4-py3-none-any.whl
python -m pypi_attestations verify dist/ainative_dev_stack-2.5.0-py3-none-any.whl
```

`SHA256SUMS` alone proves integrity against the source that published it; it
Expand Down
Loading