remem-ai 0.6.93

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
name: Release
on:
  push:
    tags: ["v*"]
  workflow_dispatch:

permissions:
  contents: write

jobs:
  preflight:
    runs-on: ubuntu-latest
    steps:
      - name: Check release ref
        run: |
          case "$GITHUB_REF" in
            refs/tags/v*) ;;
            *)
              echo "::error::Release workflow must run on a v* tag ref, got ${GITHUB_REF}"
              exit 1
              ;;
          esac
      - name: Check release secrets
        env:
          CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
          HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: |
          missing=0
          for name in CRATES_IO_TOKEN HOMEBREW_TAP_TOKEN NPM_TOKEN; do
            if [ -z "${!name}" ]; then
              echo "::error::Missing required release secret: ${name}"
              missing=1
            fi
          done
          exit "$missing"

  build:
    needs: preflight
    strategy:
      matrix:
        include:
          # local-onnx is disabled on Intel macOS: ort/ONNX Runtime ships no
          # prebuilt binaries for x86_64-apple-darwin, so the build cannot
          # link it. Embedding falls back to the feature-hash provider there
          # and the degradation is visible in `remem status` / `remem doctor`.
          - target: x86_64-apple-darwin
            os: macos-latest
            name: remem-darwin-x64
            cargo_flags: --no-default-features
          - target: aarch64-apple-darwin
            os: macos-latest
            name: remem-darwin-arm64
            cargo_flags: ""
          - target: x86_64-unknown-linux-gnu
            os: ubuntu-latest
            name: remem-linux-x64
            cargo_flags: ""
          - target: aarch64-unknown-linux-gnu
            os: ubuntu-latest
            name: remem-linux-arm64
            cargo_flags: ""
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6.0.2
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}
      - name: Install cross-compilation tools (Linux ARM64)
        if: matrix.target == 'aarch64-unknown-linux-gnu'
        run: |
          sudo apt-get update
          # g++-aarch64-linux-gnu provides the aarch64 libstdc++ that the
          # statically linked ort/ONNX Runtime (C++) needs at link time.
          sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
          echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
      - uses: Swatinem/rust-cache@v2
        with:
          key: ${{ matrix.target }}
      - run: cargo build --release --target ${{ matrix.target }} ${{ matrix.cargo_flags }}
      - name: Package binary
        run: |
          cd target/${{ matrix.target }}/release
          tar czf ../../../${{ matrix.name }}.tar.gz remem
      - uses: actions/upload-artifact@v7.0.1
        with:
          name: ${{ matrix.name }}
          path: ${{ matrix.name }}.tar.gz

  release:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6.0.2
        with:
          fetch-depth: 2
      - uses: dtolnay/rust-toolchain@1.97.0
      - name: Check version sync
        run: python3 scripts/ci/check_plugin_version_sync.py --expected-version "${GITHUB_REF_NAME#v}"
      - name: Validate surface lifecycle manifest
        run: python3 scripts/ci/check_public_surface.py
      - name: Authenticate surface lifecycle baseline
        env:
          GH_TOKEN: ${{ github.token }}
        run: python3 scripts/ci/check_surface_baseline.py "${GITHUB_SHA}^"
      - uses: actions/download-artifact@v8.0.1
        with:
          path: artifacts
      - name: Generate checksums
        run: |
          cd artifacts
          find . -name '*.tar.gz' -type f -print0 | sort -z | xargs -0 sha256sum > SHA256SUMS
      - name: Generate plugin runtime manifest
        run: python3 scripts/ci/generate_plugin_release_manifest.py "${GITHUB_REF_NAME#v}" artifacts artifacts/remem-releases.json
      - name: Include surface lifecycle manifest
        run: cp docs/specs/GH969/surface-manifest.json artifacts/surface-manifest.json
      - name: Create Release
        uses: softprops/action-gh-release@v3.0.0
        with:
          generate_release_notes: true
          files: |
            artifacts/**/*.tar.gz
            artifacts/SHA256SUMS
            artifacts/remem-releases.json
            artifacts/surface-manifest.json

  update-homebrew-tap:
    needs: release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Homebrew tap
        uses: actions/checkout@v6.0.2
        with:
          repository: majiayu000/homebrew-tap
          token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
          path: homebrew-tap
      - name: Update remem formula
        working-directory: homebrew-tap
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          set -euo pipefail

          version="${RELEASE_TAG#v}"
          base_url="https://github.com/majiayu000/remem/releases/download/v${version}"
          tmp_dir="$(mktemp -d)"
          sums="${tmp_dir}/SHA256SUMS"
          curl -fsSL "${base_url}/SHA256SUMS" -o "$sums"

          sha_for() {
            local stem="$1"
            awk -v path="./${stem}/${stem}.tar.gz" '$2 == path { print $1 }' "$sums"
          }

          darwin_arm64="$(sha_for remem-darwin-arm64)"
          darwin_x64="$(sha_for remem-darwin-x64)"
          linux_arm64="$(sha_for remem-linux-arm64)"
          linux_x64="$(sha_for remem-linux-x64)"

          for name in darwin_arm64 darwin_x64 linux_arm64 linux_x64; do
            if [ -z "${!name}" ]; then
              echo "::error::Missing checksum for ${name} in ${base_url}/SHA256SUMS"
              exit 1
            fi
          done

          mkdir -p Formula
          cat > Formula/remem.rb <<RUBY
          # typed: false
          # frozen_string_literal: true

          class Remem < Formula
            desc "Persistent memory for Claude Code and Codex"
            homepage "https://github.com/majiayu000/remem"
            version "${version}"
            license "MIT"

            on_macos do
              on_intel do
                url "${base_url}/remem-darwin-x64.tar.gz"
                sha256 "${darwin_x64}"
              end
              on_arm do
                url "${base_url}/remem-darwin-arm64.tar.gz"
                sha256 "${darwin_arm64}"
              end
            end

            on_linux do
              on_intel do
                url "${base_url}/remem-linux-x64.tar.gz"
                sha256 "${linux_x64}"
              end
              on_arm do
                url "${base_url}/remem-linux-arm64.tar.gz"
                sha256 "${linux_arm64}"
              end
            end

            def install
              bin.install "remem" => "remem"
              if OS.mac? && Hardware::CPU.arm?
                system "codesign", "--force", "--sign", "-", bin/"remem"
              end
            end

            def caveats
              <<~EOS
                Finish agent integration after installing the binary by choosing
                the agent configuration to create:

                  REMEM_INSTALL_BINARY=#{opt_bin}/remem remem install --target codex
                  REMEM_INSTALL_BINARY=#{opt_bin}/remem remem install --target claude
                  REMEM_INSTALL_BINARY=#{opt_bin}/remem remem install --target all

                If Claude Code or Codex CLI config directories already exist,
                auto-detection is also available:

                  REMEM_INSTALL_BINARY=#{opt_bin}/remem remem install

                Run remem doctor to verify or troubleshoot the integration.
              EOS
            end

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

          ruby -c Formula/remem.rb
          git add Formula/remem.rb

          if git diff --cached --quiet -- Formula/remem.rb; then
            echo "Formula/remem.rb already up to date for v${version}"
            exit 0
          fi

          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git commit -m "remem: update formula to v${version}"
          git push

  publish-crate:
    needs: release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6.0.2
      - uses: dtolnay/rust-toolchain@stable
      - name: Publish crate
        run: cargo publish --locked --token "${{ secrets.CRATES_IO_TOKEN }}"

  publish-npm:
    needs: release
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6.0.2
      - uses: actions/setup-node@v6.0.0
        with:
          node-version: 22
          registry-url: https://registry.npmjs.org
      - name: Check version sync
        run: python3 scripts/ci/check_plugin_version_sync.py --expected-version "${GITHUB_REF_NAME#v}"
      - name: Test npm wrapper
        run: node --test npm/remem/scripts/install.test.js
      - name: Smoke packed npm wrapper
        env:
          RELEASE_TAG: ${{ github.ref_name }}
        run: |
          set -euo pipefail
          version="${RELEASE_TAG#v}"
          pack_dir="$(mktemp -d)"
          install_prefix="$(mktemp -d)"
          unset REMEM_NPM_BINARY REMEM_NPM_SKIP_DOWNLOAD

          npm pack ./npm/remem --pack-destination "$pack_dir"
          tarball="$(find "$pack_dir" -maxdepth 1 -type f -name '*.tgz' -print -quit)"
          if [ -z "$tarball" ]; then
            echo "::error::npm pack did not produce a tarball"
            exit 1
          fi

          npm install --global --prefix "$install_prefix" "$tarball"
          actual="$("$install_prefix/bin/remem" --version)"
          echo "installed remem --version: $actual"
          installed_version="$(printf '%s\n' "$actual" | awk 'NR == 1 { print $2 }')"
          if [ "$installed_version" != "$version" ]; then
            echo "::error::installed remem version $installed_version does not match release tag $RELEASE_TAG"
            exit 1
          fi
      - name: Publish npm wrapper
        working-directory: npm/remem
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npm publish --access public

  publish-mcp-registry:
    needs: publish-npm
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v6.0.2
      - name: Check version sync
        run: python3 scripts/ci/check_plugin_version_sync.py --expected-version "${GITHUB_REF_NAME#v}"
      - name: Install mcp-publisher
        run: |
          set -euo pipefail
          arch="$(uname -m)"
          case "$arch" in
            x86_64) arch=amd64 ;;
            aarch64) arch=arm64 ;;
          esac
          curl -fsSL "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_${arch}.tar.gz" | tar xz mcp-publisher
      - name: Publish to MCP registry
        run: |
          set -euo pipefail
          ./mcp-publisher login github-oidc
          ./mcp-publisher publish