packages/app-core/packaging/PUBLISHING_GUIDE.md
This guide covers the human steps required to publish Eliza across all five package managers. The packaging configs are ready — this document walks through account setup, credential configuration, and publishing commands.
The eliza package on PyPI is a dynamic loader — a thin Python wrapper that auto-installs and delegates to the Node.js eliza CLI.
pypi-# Option A: Using a ~/.pypirc file
cat > ~/.pypirc << 'EOF'
[distutils]
index-servers = pypi
[pypi]
username = __token__
password = pypi-YOUR_TOKEN_HERE
EOF
chmod 600 ~/.pypirc
# Option B: Environment variable (better for CI)
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=pypi-YOUR_TOKEN_HERE
cd packaging/pypi
# Install build tools
pip install build twine
# Build the package
python -m build
# Upload to TestPyPI
twine upload --repository testpypi dist/*
# Test installation from TestPyPI
pip install --index-url https://test.pypi.org/simple/ eliza
eliza --help
cd packaging/pypi
# Build
python -m build
# Upload (uses ~/.pypirc or TWINE env vars)
twine upload dist/*
# Verify
pip install eliza
eliza --version
If you want to claim the eliza name immediately before the full release:
cd packaging/pypi
python -m build
twine upload dist/*
The beta version (2.0.0b0) is fine for name reservation.
A Homebrew "tap" is just a GitHub repo with a naming convention.
Create a GitHub repo named homebrew-tap under the eliza-ai org:
https://github.com/eliza-ai/homebrew-tapInitialize the repo:
# Clone and set up
git clone https://github.com/eliza-ai/homebrew-tap.git
cd homebrew-tap
# Copy the formula
mkdir -p Formula
cp /path/to/eliza/packaging/homebrew/eliza.rb Formula/eliza.rb
# Download the tarball and compute hash
curl -fsSL "https://registry.npmjs.org/elizaos/-/elizaos-2.0.0-beta.0.tgz" -o eliza.tgz
shasum -a 256 eliza.tgz
# Replace PLACEHOLDER_SHA256 in eliza.rb with the actual hash
git add Formula/eliza.rb
git commit -m "Add eliza formula"
git push origin main
# Test locally before pushing
brew install --build-from-source Formula/eliza.rb
# Or after pushing to the tap repo
brew tap eliza-ai/tap
brew install eliza
brew tap eliza-ai/tap
brew install eliza
Or one-liner:
brew install eliza-ai/tap/eliza
# Compute new SHA256
curl -fsSL "https://registry.npmjs.org/elizaai/-/elizaai-NEW_VERSION.tgz" -o eliza.tgz
shasum -a 256 eliza.tgz
# Update the formula: change url and sha256
# Push to homebrew-tap repo
There are two approaches: a PPA (easier, Ubuntu-focused) or a self-hosted apt repo (works with all Debian-based distros).
# Generate a GPG key
gpg --full-generate-key
# Choose RSA, 4096 bits, email matching your Launchpad account
# Upload to keyserver
gpg --send-keys YOUR_KEY_ID
# Add to Launchpad at https://launchpad.net/~/+editpgpkeys
Create a PPA:
elizaBuild and upload the source package:
cd /path/to/eliza
# Copy debian/ packaging into place
cp -r packaging/debian .
# Build the source package
dpkg-buildpackage -S -sa -k"YOUR_GPG_KEY_ID"
# Upload to PPA
dput ppa:YOUR_USERNAME/eliza ../eliza_2.0.0~beta0-1_source.changes
sudo add-apt-repository ppa:YOUR_USERNAME/eliza
sudo apt update
sudo apt install eliza
This gives you more control and works across all Debian-based distros.
cd /path/to/eliza
cp -r packaging/debian .
# Install build dependencies
sudo apt install debhelper nodejs npm
# Build the package
dpkg-buildpackage -us -uc -b
# The .deb will be in the parent directory
ls ../eliza_*.deb
# Create repo structure
mkdir -p apt-repo/pool/main/m/eliza
mkdir -p apt-repo/dists/stable/main/binary-amd64
# Copy the .deb
cp ../eliza_*.deb apt-repo/pool/main/m/eliza/
# Generate Packages index
cd apt-repo
dpkg-scanpackages pool/ /dev/null | gzip -9c > dists/stable/main/binary-amd64/Packages.gz
dpkg-scanpackages pool/ /dev/null > dists/stable/main/binary-amd64/Packages
# Create Release file
cd dists/stable
apt-ftparchive release . > Release
# Sign with GPG
gpg --armor --detach-sign -o Release.gpg Release
gpg --armor --clearsign -o InRelease Release
Host the repo (GitHub Pages, S3, Cloudflare R2, etc.)
Users install with:
# Add the GPG key
curl -fsSL https://apt.eliza.ai/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/eliza.gpg
# Add the repo
echo "deb [signed-by=/usr/share/keyrings/eliza.gpg] https://apt.eliza.ai stable main" | \
sudo tee /etc/apt/sources.list.d/eliza.list
sudo apt update
sudo apt install eliza
sudo snap install snapcraft --classic
snapcraft login
snapcraft register eliza
cd /path/to/eliza
# Copy snapcraft.yaml into place
mkdir -p snap
cp packaging/snap/snapcraft.yaml snap/
# Build the snap (requires LXD or Multipass)
snapcraft
# This produces: eliza_2.0.0-beta.0_amd64.snap
# Install the local snap
sudo snap install eliza_*.snap --classic --dangerous
# Test
eliza --version
eliza --help
# Upload to edge channel first
snapcraft upload eliza_*.snap --release=edge
# After testing, promote to stable
snapcraft release eliza <revision> stable
sudo snap install eliza --classic
# Debian/Ubuntu
sudo apt install flatpak flatpak-builder
# Fedora
sudo dnf install flatpak flatpak-builder
flatpak install flathub org.freedesktop.Platform//23.08
flatpak install flathub org.freedesktop.Sdk//23.08
Before building, you need the actual SHA256 hashes for the Node.js binaries:
# x86_64
curl -fsSL "https://nodejs.org/dist/v22.12.0/node-v22.12.0-linux-x64.tar.xz" -o node-x64.tar.xz
shasum -a 256 node-x64.tar.xz
# Replace PLACEHOLDER_SHA256_X64 in the manifest
# ARM64
curl -fsSL "https://nodejs.org/dist/v22.12.0/node-v22.12.0-linux-arm64.tar.xz" -o node-arm64.tar.xz
shasum -a 256 node-arm64.tar.xz
# Replace PLACEHOLDER_SHA256_ARM64 in the manifest
cd packaging/flatpak
# Build
flatpak-builder --repo=repo build-dir ai.eliza.Eliza.yml
# Create a bundle for testing
flatpak build-bundle repo eliza.flatpak ai.eliza.Eliza
# Install from local bundle
flatpak --user install eliza.flatpak
# Run
flatpak run ai.eliza.Eliza --version
flatpak run ai.eliza.Eliza start
github.com/flathub/ai.eliza.Elizaflatpak install flathub ai.eliza.Eliza
flatpak run ai.eliza.Eliza start
Create a Google Play Developer account at https://play.google.com/console/signup
Create the app listing:
Set up Google Play App Signing:
keytool -genkeypair -alias eliza-upload -keyalg RSA -keysize 2048 -validity 10000 -keystore eliza-upload.jks -storepass YOUR_STORE_PASSWORD -dname "CN=Eliza AI, O=eliza-ai, L=Internet, C=US"
keytool -export -alias eliza-upload -keystore eliza-upload.jks -rfc > eliza-upload-cert.pem
Upload eliza-upload-cert.pem in Play Console → App signing.
| Secret | Description |
|---|---|
ANDROID_KEYSTORE_BASE64 | base64 -w0 eliza-upload.jks |
ANDROID_KEYSTORE_PASSWORD | Keystore password |
ANDROID_KEY_ALIAS | eliza-upload |
ANDROID_KEY_PASSWORD | Key password |
PLAY_STORE_SERVICE_ACCOUNT_JSON | base64 -w0 play-store-key.json |
cd apps/app
# Build web assets
bun run build
# Sync to Android
npx cap sync android
# Build signed AAB
cd android
ELIZA_KEYSTORE_PATH=/path/to/eliza-upload.jks ELIZA_KEYSTORE_PASSWORD=yourpass ELIZA_KEY_ALIAS=eliza-upload ELIZA_KEY_PASSWORD=yourpass ./gradlew bundleRelease
# AAB is at app/build/outputs/bundle/release/app-release.aab
cd apps/app/android
# Install Fastlane
bundle install
# Upload to internal testing
PLAY_STORE_JSON_KEY=/path/to/play-store-key.json ELIZA_KEYSTORE_PATH=/path/to/eliza-upload.jks ELIZA_KEYSTORE_PASSWORD=yourpass ELIZA_KEY_ALIAS=eliza-upload ELIZA_KEY_PASSWORD=yourpass bundle exec fastlane internal
# Promote to beta
bundle exec fastlane beta
# Promote to production
bundle exec fastlane production
Complete these in Play Console before first release:
fastlane/metadata/android/en-US/)| Question | Answer |
|---|---|
| Does the app collect data? | Yes (user-provided API keys, chat messages) |
| Is data shared with third parties? | Yes (AI providers: Anthropic, OpenAI, etc. — user-selected) |
| Is data encrypted in transit? | Yes (HTTPS to all AI providers) |
| Can users request data deletion? | Yes (local data, users delete the app or clear data) |
| Data stored on device | API keys, chat history, agent configuration |
| Data sent to servers | Chat messages to user-selected AI provider |
The repo now uses a two-stage release model:
agent-release.yml validates the heavy build matrix and publishes the GitHub Release only after the blocking lanes are green.release-orchestrator.yml handles post-release distribution and fans out to reusable child workflows:
publish-npm.ymlpublish-packages.ymlandroid-release.ymlapple-store-release.ymlupdate-homebrew.ymldeploy-web.ymlWhy this split exists:
latest for stable, next / beta / nightly for prereleasesproduction for stable, internal for prereleasesapp-store for stable, testflight for prereleasesManual recovery path:
# Re-run only the post-release distribution layer for an existing release
gh workflow run release-orchestrator.yml -f version=2.0.0-beta.0
| Secret | Where to get it | Used by |
|---|---|---|
SNAP_STORE_CREDENTIALS | snapcraft export-login --snaps=eliza --acls=package_push - | Snap publishing |
HOMEBREW_TAP_TOKEN | GitHub PAT with repo scope for eliza-ai/homebrew-tap | Homebrew formula updates |
PYPI_API_TOKEN | https://pypi.org/manage/account/token/ (or use trusted publishing) | PyPI uploads |
ANDROID_KEYSTORE_BASE64 | base64 -w0 eliza-upload.jks | Android AAB signing |
ANDROID_KEYSTORE_PASSWORD | Android upload keystore password | Android AAB signing |
ANDROID_KEY_ALIAS | Android upload key alias | Android AAB signing |
ANDROID_KEY_PASSWORD | Android upload key password | Android AAB signing |
PLAY_STORE_SERVICE_ACCOUNT_JSON | Google Cloud Console service account JSON (base64) | Play Store uploads |
APPLE_ID | Apple ID email | Apple store publishing |
APPLE_TEAM_ID | 10-char Apple team ID | Apple store publishing |
APPLE_APP_SPECIFIC_PASSWORD | App-specific password from appleid.apple.com | Apple store publishing |
Instead of API tokens, use OIDC trusted publishing:
eliza-aielizapublish-packages.ymlThis eliminates the need for PYPI_API_TOKEN — GitHub Actions authenticates directly.
ai.eliza.app, enable Push Notificationseliza-ai/certificates for Fastlane Matchai.eliza.app| Secret | Description |
|---|---|
APPLE_ID | Apple ID email |
APPLE_TEAM_ID | 10-char Apple Developer Team ID |
APPLE_APP_SPECIFIC_PASSWORD | Generated at appleid.apple.com |
ITC_TEAM_ID | App Store Connect team ID |
APP_STORE_APP_ID | Numeric Apple ID from App Store Connect |
MATCH_PASSWORD | Encryption password for Match certificates |
MATCH_GIT_URL | URL to certificates repo |
MATCH_GIT_BASIC_AUTHORIZATION | base64(username:PAT) for certificates repo |
| Data Type | Collected | Linked to Identity | Tracking |
|---|---|---|---|
| Usage Data | Yes | No | No |
| Location | Yes (optional) | No | No |
| Photos | Yes (optional) | No | No |
| User Content (chat) | Yes | No | No |
Data is stored on-device only. Chat messages sent to user-selected AI provider.
| Secret | Description |
|---|---|
MAS_CSC_LINK | base64-encoded Apple Distribution .p12 |
MAS_CSC_KEY_PASSWORD | Password for the .p12 |
MAS_INSTALLER_CERT | base64-encoded 3rd Party Mac Developer Installer .p12 |
MAS_INSTALLER_KEY_PASSWORD | Password for installer .p12 |
APP_STORE_API_KEY_ID | App Store Connect API key ID |
APP_STORE_API_ISSUER_ID | App Store Connect API issuer ID |
Mac App Store requires App Sandbox. Entitlements at
apps/app/electrobun/entitlements/mas.entitlements configure network,
file access, camera, microphone, and JIT compilation for Bun runtime.
When releasing a new version, update these files:
| File | Field to Update |
|---|---|
package.json | version |
packaging/pypi/pyproject.toml | version (use PEP 440: 2.0.0b0 not 2.0.0-beta.0) |
packaging/pypi/eliza/__init__.py | __version__ |
packaging/snap/snapcraft.yaml | version |
packaging/debian/changelog | Add new entry at top |
packaging/homebrew/eliza.rb | url + sha256 (after npm publish) |
packaging/flatpak/ai.eliza.Eliza.metainfo.xml | Add new <release> entry |
apps/app/android/app/build.gradle | versionCode + versionName (via env vars in CI) |
| Platform | Format | Example |
|---|---|---|
| npm | semver pre-release | 2.0.0-beta.0 |
| PyPI (PEP 440) | beta suffix | 2.0.0b0 |
| Debian | tilde for pre-release | 2.0.0~beta0-1 |
| Snap | semver-ish | 2.0.0-beta.0 |
| Flatpak | semver | 2.0.0-beta.0 |
| Homebrew | follows npm tarball URL | (automatic) |
| Platform | Command |
|---|---|
| npm | npm install -g elizaai |
| PyPI | pip install eliza |
| Homebrew | brew install eliza-ai/tap/eliza |
| apt | sudo apt install eliza (after adding repo) |
| Snap | sudo snap install eliza --classic |
| Flatpak | flatpak install flathub ai.eliza.Eliza |
| Google Play | Search "Eliza" on Play Store |
| iOS App Store | Search "Eliza" on App Store |
| Mac App Store | Search "Eliza" on Mac App Store |
| npx | npx elizaai (no install) |
| pipx | pipx install eliza |