aidaemon 0.11.6

A personal AI agent that runs as a background daemon, accessible via Telegram, Slack, or Discord, with tool use, MCP integration, and persistent memory
Documentation
name: Release

on:
  push:
    tags:
      - 'v*'

env:
  CARGO_TERM_COLOR: always

jobs:
  quality-gate:
    name: Quality gate
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v5

      - uses: dtolnay/rust-toolchain@stable

      - name: Install Linux dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libdbus-1-dev pkg-config libssl-dev

      - name: Free disk space
        run: |
          sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL
          sudo docker image prune --all --force || true
          df -h

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
          key: ${{ runner.os }}-cargo-release-gate-v2-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-release-gate-v2-

      - name: Cache fastembed model
        uses: actions/cache@v4
        with:
          path: .fastembed_cache
          key: fastembed-allminilml6v2-v2

      - name: Run tests
        run: cargo test --all-features

  build:
    name: Build ${{ matrix.name }}
    needs: [quality-gate]
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            name: linux-x86_64
            cross: false

          # TODO: Add linux-aarch64 when cross-compilation for fastembed/ONNX is resolved
          # - target: aarch64-unknown-linux-gnu
          #   os: ubuntu-latest
          #   name: linux-aarch64
          #   cross: true

          - target: x86_64-apple-darwin
            os: macos-15
            name: macos-x86_64
            cross: false

          - target: aarch64-apple-darwin
            os: macos-14
            name: macos-aarch64
            cross: false

    steps:
      - name: Checkout
        uses: actions/checkout@v5

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install cross
        if: matrix.cross
        run: cargo install cross --git https://github.com/cross-rs/cross

      - name: Install Linux dependencies
        if: matrix.os == 'ubuntu-latest' && !matrix.cross
        run: |
          sudo apt-get update
          sudo apt-get install -y libdbus-1-dev pkg-config libssl-dev

      - name: Build (native)
        if: '!matrix.cross'
        run: cargo build --release --target ${{ matrix.target }} --features "browser"

      - name: Build (cross)
        if: matrix.cross
        run: cross build --release --target ${{ matrix.target }}

      - name: Package (Unix)
        run: |
          cd target/${{ matrix.target }}/release
          tar -czvf ../../../aidaemon-${{ matrix.name }}.tar.gz aidaemon
          cd ../../..
          shasum -a 256 aidaemon-${{ matrix.name }}.tar.gz > aidaemon-${{ matrix.name }}.tar.gz.sha256

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: aidaemon-${{ matrix.name }}
          path: |
            aidaemon-${{ matrix.name }}.tar.gz
            aidaemon-${{ matrix.name }}.tar.gz.sha256

  release:
    name: Create Release
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout
        uses: actions/checkout@v5

      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
          merge-multiple: true

      - name: Create Release
        uses: softprops/action-gh-release@v2
        with:
          draft: false
          generate_release_notes: true
          files: |
            artifacts/*.tar.gz
            artifacts/*.sha256

  publish-crates:
    name: Publish to crates.io
    needs: release
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - name: Checkout
        uses: actions/checkout@v5

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Validate tag matches crate version
        id: release_meta
        run: |
          set -euo pipefail

          TAG_VERSION="${GITHUB_REF_NAME#v}"
          CRATE_VERSION="$(
            awk '
              /^\[package\]$/ { in_package=1; next }
              /^\[/ && in_package { exit }
              in_package && /^version = / {
                gsub(/^version = "/, "", $0)
                gsub(/"$/, "", $0)
                print
                exit
              }
            ' Cargo.toml
          )"

          echo "tag_version=${TAG_VERSION}" >> "$GITHUB_OUTPUT"
          echo "crate_version=${CRATE_VERSION}" >> "$GITHUB_OUTPUT"

          if [ "$TAG_VERSION" != "$CRATE_VERSION" ]; then
            echo "::error::Tag ${GITHUB_REF_NAME} does not match Cargo.toml version ${CRATE_VERSION}."
            exit 1
          fi

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libdbus-1-dev pkg-config libssl-dev

      - name: Publish
        id: publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          set -euo pipefail

          if [ -z "${CARGO_REGISTRY_TOKEN:-}" ]; then
            echo "::error::CARGO_REGISTRY_TOKEN is not configured."
            exit 1
          fi

          LOG_FILE="$(mktemp)"

          set +e
          cargo publish --token "$CARGO_REGISTRY_TOKEN" 2>&1 | tee "$LOG_FILE"
          STATUS=${PIPESTATUS[0]}
          set -e

          if [ "$STATUS" -eq 0 ]; then
            echo "result=published" >> "$GITHUB_OUTPUT"
            exit 0
          fi

          if grep -Eqi 'already (uploaded|exists|been uploaded)|crate version .* is already uploaded' "$LOG_FILE"; then
            echo "result=already-published" >> "$GITHUB_OUTPUT"
            exit 0
          fi

          echo "::error::cargo publish failed for version ${{ steps.release_meta.outputs.crate_version }}."
          exit "$STATUS"

      - name: Verify crates.io version
        env:
          EXPECTED_VERSION: ${{ steps.release_meta.outputs.crate_version }}
          PUBLISH_RESULT: ${{ steps.publish.outputs.result }}
        run: |
          set -euo pipefail

          echo "Waiting for crates.io to report aidaemon ${EXPECTED_VERSION} (${PUBLISH_RESULT})."

          for ATTEMPT in $(seq 1 30); do
            REPORTED_VERSION="$(
              python3 -c 'import json, urllib.request; payload = json.load(urllib.request.urlopen("https://crates.io/api/v1/crates/aidaemon", timeout=20)); print(payload["crate"]["max_version"])'
            )"

            if [ "$REPORTED_VERSION" = "$EXPECTED_VERSION" ]; then
              echo "crates.io now reports aidaemon ${REPORTED_VERSION}."
              exit 0
            fi

            echo "Attempt ${ATTEMPT}/30: crates.io reports ${REPORTED_VERSION}; waiting for ${EXPECTED_VERSION}."
            sleep 10
          done

          echo "::error::crates.io did not report aidaemon ${EXPECTED_VERSION} within 5 minutes."
          exit 1

  update-homebrew:
    name: Update Homebrew Tap
    needs: release
    runs-on: ubuntu-latest
    steps:
      - name: Get release info
        id: release
        run: |
          VERSION="${GITHUB_REF_NAME#v}"
          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          echo "tag=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"

      - name: Download release assets and compute SHA256
        id: sha
        run: |
          BASE_URL="https://github.com/${{ github.repository }}/releases/download/${{ steps.release.outputs.tag }}"

          curl -sL "${BASE_URL}/aidaemon-macos-aarch64.tar.gz" -o macos-aarch64.tar.gz
          curl -sL "${BASE_URL}/aidaemon-macos-x86_64.tar.gz" -o macos-x86_64.tar.gz
          curl -sL "${BASE_URL}/aidaemon-linux-x86_64.tar.gz" -o linux-x86_64.tar.gz

          echo "macos_arm64=$(sha256sum macos-aarch64.tar.gz | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
          echo "macos_x86_64=$(sha256sum macos-x86_64.tar.gz | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
          echo "linux_x86_64=$(sha256sum linux-x86_64.tar.gz | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"

      - name: Checkout tap
        uses: actions/checkout@v5
        with:
          repository: davo20019/homebrew-tap
          token: ${{ secrets.HOMEBREW_TAP_TOKEN }}

      - name: Update formula
        run: |
          mkdir -p Formula
          cat > Formula/aidaemon.rb << 'RUBY'
          class Aidaemon < Formula
            desc "Personal AI agent daemon with tool use, MCP integration, and persistent memory"
            homepage "https://aidaemon.ai/"
            license "MIT"
            version "VERSION_PLACEHOLDER"

            on_macos do
              if Hardware::CPU.arm?
                url "https://github.com/davo20019/aidaemon/releases/download/vVERSION_PLACEHOLDER/aidaemon-macos-aarch64.tar.gz"
                sha256 "SHA_MACOS_ARM64_PLACEHOLDER"
              else
                url "https://github.com/davo20019/aidaemon/releases/download/vVERSION_PLACEHOLDER/aidaemon-macos-x86_64.tar.gz"
                sha256 "SHA_MACOS_X86_64_PLACEHOLDER"
              end
            end

            on_linux do
              url "https://github.com/davo20019/aidaemon/releases/download/vVERSION_PLACEHOLDER/aidaemon-linux-x86_64.tar.gz"
              sha256 "SHA_LINUX_X86_64_PLACEHOLDER"
            end

            def install
              bin.install "aidaemon"
            end

            test do
              assert_match "aidaemon", shell_output("#{bin}/aidaemon --version", 0)
            end
          end
          RUBY

          sed -i "s/VERSION_PLACEHOLDER/${{ steps.release.outputs.version }}/g" Formula/aidaemon.rb
          sed -i "s/SHA_MACOS_ARM64_PLACEHOLDER/${{ steps.sha.outputs.macos_arm64 }}/g" Formula/aidaemon.rb
          sed -i "s/SHA_MACOS_X86_64_PLACEHOLDER/${{ steps.sha.outputs.macos_x86_64 }}/g" Formula/aidaemon.rb
          sed -i "s/SHA_LINUX_X86_64_PLACEHOLDER/${{ steps.sha.outputs.linux_x86_64 }}/g" Formula/aidaemon.rb

      - name: Commit and push
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add Formula/aidaemon.rb
          git commit -m "Update aidaemon to ${{ steps.release.outputs.version }}"
          git push