diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..39f8b9a1 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,24 @@ +name: Publish to PyPI + +on: + release: + types: [published] + +permissions: + id-token: write + +jobs: + publish: + runs-on: ubuntu-latest + environment: pypi + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v6 + + - name: Build package + run: uv build + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/update-homebrew.yml b/.github/workflows/update-homebrew.yml new file mode 100644 index 00000000..2af47db9 --- /dev/null +++ b/.github/workflows/update-homebrew.yml @@ -0,0 +1,62 @@ +name: Update Homebrew Formula + +on: + release: + types: [published] + workflow_dispatch: + inputs: + version: + description: "Version tag (e.g., v0.1.0)" + required: true + +jobs: + update-formula: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Determine version + id: version + run: | + if [ "${{ github.event_name }}" = "release" ]; then + echo "tag=${{ github.event.release.tag_name }}" >> "$GITHUB_OUTPUT" + else + echo "tag=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT" + fi + + - name: Download and hash release tarball + id: hash + run: | + TAG="${{ steps.version.outputs.tag }}" + URL="https://github.com/microsoft/amplifier/archive/refs/tags/${TAG}.tar.gz" + curl -sL "$URL" -o release.tar.gz + SHA=$(shasum -a 256 release.tar.gz | awk '{print $1}') + echo "sha256=${SHA}" >> "$GITHUB_OUTPUT" + echo "url=${URL}" >> "$GITHUB_OUTPUT" + + - name: Update formula + run: | + TAG="${{ steps.version.outputs.tag }}" + VERSION="${TAG#v}" + SHA="${{ steps.hash.outputs.sha256 }}" + URL="${{ steps.hash.outputs.url }}" + + FORMULA="homebrew-amplifier/Formula/amplifier.rb" + + sed -i "s|url \".*\"|url \"${URL}\"|" "$FORMULA" + sed -i "s|sha256 \".*\"|sha256 \"${SHA}\"|" "$FORMULA" + + # Update version if present in the formula + echo "Updated formula to version ${VERSION} (sha256: ${SHA})" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + title: "Update Homebrew formula to ${{ steps.version.outputs.tag }}" + body: | + Automated update of the Homebrew formula for Amplifier. + + - Version: `${{ steps.version.outputs.tag }}` + - SHA256: `${{ steps.hash.outputs.sha256 }}` + branch: "update-formula-${{ steps.version.outputs.tag }}" + commit-message: "Update Homebrew formula to ${{ steps.version.outputs.tag }}" diff --git a/README.md b/README.md index 5aa28e42..520211b2 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,16 @@ Amplifier brings AI assistance to your command line with a modular, extensible a > [!IMPORTANT] > Amplifier is currently developed and tested on macOS, Linux, and Windows Subsystem for Linux (WSL). Native Windows shells have known issues—use WSL unless you're actively contributing Windows fixes. -### Step 1: Install UV (30 seconds) +### Option A: Install with Homebrew (macOS/Linux) + +```bash +brew tap microsoft/amplifier +brew install amplifier +``` + +### Option B: Install with UV + +#### Step 1: Install UV (30 seconds) ```bash # macOS/Linux/WSL @@ -33,13 +42,13 @@ curl -LsSf https://astral.sh/uv/install.sh | sh powershell -c "irm https://astral.sh/uv/install.ps1 | iex" ``` -### Step 2: Install Amplifier (30 seconds) +#### Step 2: Install Amplifier (30 seconds) ```bash uv tool install git+https://github.com/microsoft/amplifier ``` -### Step 3: Run Amplifier (30 seconds) +### Run Amplifier ```bash # First-time wizard (auto-detects missing config) diff --git a/amplifier/__init__.py b/amplifier/__init__.py new file mode 100644 index 00000000..0a1e7a20 --- /dev/null +++ b/amplifier/__init__.py @@ -0,0 +1,3 @@ +"""Amplifier AI development platform - modular AI assistant.""" + +__version__ = "0.1.0" diff --git a/docs/PUBLISHING.md b/docs/PUBLISHING.md new file mode 100644 index 00000000..cc8b6d31 --- /dev/null +++ b/docs/PUBLISHING.md @@ -0,0 +1,171 @@ +# Publishing Guide + +This guide covers how to publish Amplifier to PyPI and update the Homebrew formula. + +## PyPI Trusted Publishing Setup + +Amplifier uses GitHub Actions with OpenID Connect (OIDC) for secure, keyless publishing to PyPI. This eliminates the need for API tokens. + +### Prerequisites + +1. A PyPI account with permissions to create new projects (or manage the `amplifier` project) +2. Admin access to the `microsoft/amplifier` GitHub repository + +### Step 1: Create the PyPI Project + +1. Go to [PyPI](https://pypi.org/) and log in +2. If this is the first release: + - The project will be created automatically on first publish + - Ensure your PyPI account is verified (email confirmation) + +### Step 2: Configure Trusted Publishing on PyPI + +1. Go to your PyPI project page (after first release) or pre-register at: https://pypi.org/manage/account/publishing/ +2. Navigate to "Publishing" → "Add a new publisher" +3. Fill in the form: + - **PyPI Project Name**: `amplifier` + - **Owner**: `microsoft` + - **Repository name**: `amplifier` + - **Workflow name**: `publish.yml` + - **Environment name**: `pypi` (must match the environment in `.github/workflows/publish.yml`) +4. Click "Add" + +### Step 3: Create GitHub Environment + +1. Go to GitHub: `https://github.com/microsoft/amplifier/settings/environments` +2. Click "New environment" +3. Name it: `pypi` (must match PyPI configuration) +4. Configure environment protection rules (recommended): + - ✅ Required reviewers (optional but recommended for production) + - ✅ Restrict to specific branches: `main` +5. Click "Save protection rules" + +### Step 4: Test the Workflow + +1. Create a test release or manually trigger the workflow +2. The workflow should: + - Build the package with `uv build` + - Publish to PyPI using OIDC (no API tokens needed) + - Complete without errors + +### Troubleshooting + +**Error: "Permission denied" or "OIDC token not found"** +- Ensure the `pypi` environment exists in GitHub +- Verify the workflow has `permissions: id-token: write` +- Check that the environment name matches in both PyPI and GitHub + +**Error: "Project does not exist"** +- For first-time publishing, you may need to pre-register the project name on PyPI +- Go to: https://pypi.org/manage/account/publishing/ + +**Error: "Publishing not configured"** +- Double-check the PyPI trusted publisher settings +- Ensure owner/repo/workflow/environment names match exactly + +## Publishing a New Release + +### 1. Prepare the Release + +```bash +# Ensure all changes are committed and pushed +git checkout main +git pull origin main + +# Update version in pyproject.toml if needed +# Update CHANGELOG.md with release notes +``` + +### 2. Create and Push a Git Tag + +```bash +# Create an annotated tag +git tag -a v0.1.0 -m "Release v0.1.0" + +# Push the tag +git push origin v0.1.0 +``` + +### 3. Create a GitHub Release + +1. Go to: `https://github.com/microsoft/amplifier/releases/new` +2. Select the tag you just created (e.g., `v0.1.0`) +3. Title: `v0.1.0` +4. Description: Copy from CHANGELOG.md or write release notes +5. Click "Publish release" + +### 4. Automated Publishing + +Once you create a GitHub release: + +1. **PyPI Publishing** (`.github/workflows/publish.yml`): + - Triggers automatically on release + - Builds the package with `uv build` + - Publishes to PyPI via trusted publishing + - ✅ Check: https://pypi.org/project/amplifier/ + +2. **Homebrew Formula Update** (`.github/workflows/update-homebrew.yml`): + - Triggers automatically on release + - Downloads the release tarball + - Calculates SHA256 hash + - Creates a PR to update `homebrew-amplifier/Formula/amplifier.rb` + - ⚠️ Review and merge the auto-generated PR + +### 5. Verify the Release + +```bash +# Test PyPI installation +uv pip install amplifier +amplifier --version + +# Test Homebrew installation (after merging formula PR) +brew update +brew upgrade amplifier +amplifier --version +``` + +## Homebrew Tap Setup + +### First-Time Setup + +The Homebrew formula lives in this repo under `homebrew-amplifier/`. After the first release: + +1. Create a separate tap repository: `microsoft/homebrew-amplifier` +2. Copy contents from `homebrew-amplifier/` to the new repo +3. Users can then install with: + ```bash + brew tap microsoft/amplifier + brew install amplifier + ``` + +### Manual Formula Updates + +If the automated workflow fails, update the formula manually: + +```bash +# Download and hash the release tarball +VERSION="v0.1.0" +curl -sL "https://github.com/microsoft/amplifier/archive/refs/tags/${VERSION}.tar.gz" | shasum -a 256 + +# Update homebrew-amplifier/Formula/amplifier.rb +# Replace the url and sha256 values +# Create a PR with the changes +``` + +## Dependencies + +### Publishing Dependencies to PyPI + +Before publishing `amplifier` to PyPI, ensure dependencies are also published: + +- ✅ `amplifier-core` - Check [PyPI](https://pypi.org/project/amplifier-core/) +- ✅ `amplifier-app-cli` - Check [PyPI](https://pypi.org/project/amplifier-app-cli/) + +If dependencies are not on PyPI yet, they must be published first, or keep using git references in `[tool.uv.sources]` for development. + +## Security Notes + +- ✅ **No API tokens stored** - Trusted publishing uses short-lived OIDC tokens +- ✅ **Environment protection** - GitHub environments add approval gates +- ✅ **Automated formula updates** - Reduces manual errors in SHA256 hashes +- ⚠️ Always verify the SHA256 hash matches the release tarball before merging Homebrew PRs diff --git a/homebrew-amplifier/Formula/amplifier.rb b/homebrew-amplifier/Formula/amplifier.rb new file mode 100644 index 00000000..7abb10bb --- /dev/null +++ b/homebrew-amplifier/Formula/amplifier.rb @@ -0,0 +1,35 @@ +class Amplifier < Formula + desc "AI-powered modular development assistant" + homepage "https://github.com/microsoft/amplifier" + url "https://github.com/microsoft/amplifier/archive/refs/tags/v0.1.0.tar.gz" + # TODO: Update SHA256 after v0.1.0 is tagged. Calculate with: + # curl -sL https://github.com/microsoft/amplifier/archive/refs/tags/v0.1.0.tar.gz | shasum -a 256 + sha256 "PLACEHOLDER_SHA256" + license "MIT" + + head "https://github.com/microsoft/amplifier.git", branch: "main" + + depends_on "uv" + depends_on "python@3.12" + + # Pre-built Python wheels (e.g. pydantic_core) have compiled extensions + # whose Mach-O headers cannot be rewritten by Homebrew's relocator. + # This is harmless — the extensions work correctly without relocation. + skip_clean "libexec" + + def install + python = Formula["python@3.12"].opt_bin/"python3.12" + venv = libexec + + # uv sync respects [tool.uv.sources] and uv.lock for reproducible installs + # (including git-sourced packages not yet published to PyPI) + ENV["UV_PROJECT_ENVIRONMENT"] = venv.to_s + system "uv", "sync", "--frozen", "--no-dev", "--python", python + + (bin/"amplifier").write_env_script(venv/"bin/amplifier", PATH: "#{venv}/bin:$PATH") + end + + test do + assert_match "amplifier", shell_output("#{bin}/amplifier --version") + end +end diff --git a/homebrew-amplifier/README.md b/homebrew-amplifier/README.md new file mode 100644 index 00000000..e71804e2 --- /dev/null +++ b/homebrew-amplifier/README.md @@ -0,0 +1,41 @@ +# Homebrew Tap for Amplifier + +This is the official [Homebrew](https://brew.sh) tap for [Amplifier](https://github.com/microsoft/amplifier), an AI-powered modular development assistant. + +## Installation + +```bash +brew tap microsoft/amplifier +brew install amplifier +``` + +## Updating + +```bash +brew update +brew upgrade amplifier +``` + +## Development Install (HEAD) + +To install the latest development version from the `main` branch: + +```bash +brew install --HEAD amplifier +``` + +## Requirements + +- macOS or Linux +- Python 3.12+ (installed automatically by Homebrew) +- [uv](https://docs.astral.sh/uv/) (installed automatically by Homebrew) + +## Troubleshooting + +If you encounter issues, try: + +```bash +brew reinstall amplifier +``` + +Or file an issue at [microsoft/amplifier](https://github.com/microsoft/amplifier/issues). diff --git a/pyproject.toml b/pyproject.toml index 9fce1c59..62e8eb8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,11 +8,31 @@ requires-python = ">=3.11" authors = [ { name = "Microsoft MADE:Explorations Team" }, ] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Software Development", + "Topic :: Software Development :: Libraries :: Application Frameworks", +] dependencies = [ "amplifier-core", - "amplifier-app-cli @ git+https://github.com/microsoft/amplifier-app-cli@main", + # amplifier-app-cli will be published to PyPI before this PR merges + # During development, it resolves via git reference in [tool.uv.sources] + # Note: Ensure amplifier-app-cli is versioned >= 0.1.0 before PyPI publish + "amplifier-app-cli>=0.1.0", ] +[project.urls] +Homepage = "https://github.com/microsoft/amplifier" +Repository = "https://github.com/microsoft/amplifier" +Issues = "https://github.com/microsoft/amplifier/issues" + [project.scripts] amplifier = "amplifier_app_cli.main:main" @@ -32,6 +52,3 @@ amplifier-app-cli = { git = "https://github.com/microsoft/amplifier-app-cli", br packages = [ "amplifier", ] - -[tool.hatch.metadata] -allow-direct-references = true