Skip to content

Releasing daari

Human-gated by design — agents prepare, a maintainer pulls the trigger.

Checklist

  1. Bump version in pyproject.toml and daari.__version__; move CHANGELOG.md Unreleased → new section.
  2. Write docs/RELEASE-vX.Y.Z.md (scope, highlights, validation results). Put Human steps remaining at the top — agents must not tag, create a GitHub release, or publish.
  3. Verify this file against current workflows (especially docker.yml cosign / SBOM / provenance from #311).
  4. Merge via PR (CI checks). Then tag + GitHub release:
git tag vX.Y.Z && git push origin vX.Y.Z
gh release create vX.Y.Z --title "vX.Y.Z — <name>" --notes-file docs/RELEASE-vX.Y.Z.md

What automation does from there

Artifact Workflow Trigger Gate
PyPI package publish.yml GitHub release published (or manual dispatch, incl. TestPyPI) Trusted publisher registered 2026-08-13
Docker image docker.yml tag push → ghcr.io/naveenreddyalka/daari:vX.Y.Z + latest on main ghcr package visibility (first publish creates it)
Image signature docker.yml (cosign keyless) same push as the image (non-PR) OIDC id-token: write; signs IMAGE@DIGEST
SBOM + provenance docker.yml (sbom: true, provenance: true on build-push) attached to the pushed image no-op on PR builds (push: false)
Docs site docs-site.yml push to main GitHub Pages (auto-enabled)

The build job runs twine check --strict on the sdist/wheel before any upload.

Verify a signed image (after the tag push)

cosign verify \
  --certificate-identity-regexp 'https://github.com/naveenreddyalka/daari/.github/workflows/docker.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  ghcr.io/naveenreddyalka/daari:vX.Y.Z

Inspect SBOM / provenance attestations with docker buildx imagetools inspect or cosign download sbom / cosign download attestation against the image digest from the docker.yml run.

PyPI trusted publisher

Registered 2026-08-13. daari==1.2.0 is on PyPI. v1.1.1 / v1.1.2 / the first v1.2.0 attempt failed invalid-publisher because this form had not been filled in; a failed publish does not fail the GitHub release, so it went unnoticed three times.

scripts/release_pypi.py is the release path from here:

python scripts/release_pypi.py check                    # what is blocking, changes nothing
python scripts/release_pypi.py publish --target testpypi # optional dry run
python scripts/release_pypi.py publish --target pypi      # triggers, watches, diagnoses
python scripts/release_pypi.py verify --version X.Y.Z     # clean-venv install check

publish reruns the failed job from the tag's own release run when one exists, so the upload matches the tag instead of whatever main currently holds. It refuses to publish a version already on the index, since PyPI uploads cannot be replaced, and decodes an invalid-publisher failure back into the claim values to fix.

The publisher is already on the project. Recreate it only if PyPI drops the registration, using exactly these OIDC claims — they must match the workflow:

Field Value
PyPI Project Name daari
Owner naveenreddyalka
Repository name daari
Workflow name publish.yml
Environment name pypi

No API token is created or stored. For a version that already has a tag but never reached the index, re-run just the failed job so it keeps the tag's ref:

gh run rerun $(gh run list --workflow publish.yml --limit 1 --json databaseId -q '.[0].databaseId') --failed

Dry-run against TestPyPI first if you prefer — it needs its own publisher with environment testpypi:

gh workflow run publish.yml -f repository=testpypi

Verify: pip install daari==X.Y.Z in a clean venv, then daari --help.

Homebrew formula

Formula/daari.rb needs the release tarball's sha256 plus a resource block for every transitive dependency, because Homebrew builds with no network access and virtualenv_install_with_resources installs only what the formula declares. Both are generated — never hand-edited:

python scripts/update_formula.py --version X.Y.Z

The formula cannot be installed from a path — Homebrew 6 rejects formulae outside a tap (Error: Homebrew requires formulae to be in a tap). It is served from naveenreddyalka/homebrew-daari; after regenerating, copy the file into that repo. Users additionally need brew trust naveenreddyalka/daari, which Homebrew 6 requires for third-party taps.

To validate a change without touching the public tap, use a throwaway local tap — brew fetch verifies every checksum without installing:

brew tap-new --no-git naveenreddyalka/formulatest
cp Formula/daari.rb "$(brew --repository naveenreddyalka/formulatest)/Formula/"
brew fetch --formula --build-from-source naveenreddyalka/formulatest/daari
brew untap naveenreddyalka/formulatest

After release

  • Verify pip install daari==X.Y.Z in a clean venv.
  • Local deploy: the launchd watchdog redeploys main and runs live E2E within 2h.
  • Update CONTEXT.md current-phase line and docs/TRACKING.md.