Publishing and Module Store Guide
Publish your developed modules or adapters to the ErisPulse Module Store, allowing other users to easily discover and install them.
Module Store Overview
The ErisPulse Module Store is a centralized module registry, where users can browse, search, and install community-contributed modules and adapters through the CLI tool.
Browsing and Discovery
# List all available packages remotely
epsdk list-remote
# Show only modules
epsdk list-remote -t modules
# Show only adapters
epsdk list-remote -t adapters
# Force refresh the remote package list
epsdk list-remote -r
You can also browse the Module Store online at ErisPulse's official website.
Supported Submission Types
| Type | Description | Entry-point Group |
|---|---|---|
| Module | Extend bot functionality, implement business logic | erispulse.module |
| Adapter | Connect to new messaging platforms | erispulse.adapter |
Quick Publish
The entire process consists of three steps: configure the project → publish to PyPI → submit to the Module Store.
1. Configure pyproject.toml
Ensure your project directory contains pyproject.toml and README.md, and configure entry-points according to the type:
Module
[project]
name = "ErisPulse-MyModule"
version = "1.0.0"
description = "Module function description"
requires-python = ">=3.10"
license = { text = "MIT" }
authors = [ { name = "yourname" } ]
dependencies = [
"ErisPulse>=2.0.0",
]
[project.entry-points."erispulse.module"]
"MyModule" = "MyModule:Main"
Adapter
[project]
name = "ErisPulse-MyAdapter"
version = "1.0.0"
description = "Adapter function description"
requires-python = ">=3.10"
[project.entry-points."erispulse.adapter"]
"myplatform" = "MyAdapter:MyAdapter"
Note: It is recommended that package names start with
ErisPulse-for easy identification. The entry-point key (e.g.,"MyModule") will serve as the module's access name in the SDK.
2. Publish to PyPI
# Build + Publish (requires a PyPI account)
pip install build twine
python -m build
python -m twine upload dist/*
After successful publication, verify the installation:
pip install ErisPulse-MyModule
3. Submit to the Module Store
Go to the ErisPulse Module Store, click "Submit Module", log in, and fill in the module information.
Supported login methods: GitHub, Codeberg, Cloud Lake. You can choose any one.
Key points to fill:
- Module name, description, repository address
- Minimum SDK version: If unsure, fill in the version number of the latest ErisPulse release
After submission, it takes effect immediately, and users can install it via the module source. The module will be marked as "unverified", and will be changed to "verified" after the maintainer's review.
About verification status:
- "Unverified" only means it has not been officially reviewed, not that the module has problems
- When users install unverified modules via
epsdk install, they will receive a risk warning, and must confirm to continue installation
4. Manage Published Modules
After clicking "Submit Module" and logging in on the Module Store, switch to the "My Modules" tab, where you can:
- Edit — Modify module description, repository address, tags, etc. The version number will be automatically synchronized from PyPI
- Delete — Remove the module from the Module Store (irreversible)
Newly submitted modules may take a few minutes to appear in the "My Modules" list.
Update Published Modules
- Update the
versioninpyproject.toml - Rebuild and upload:
python -m build && python -m twine upload dist/* - The Module Store will automatically synchronize the latest version from PyPI
Users can upgrade via epsdk upgrade MyModule.
Pre-publish Checklist
Before pushing to PyPI, please confirm the following items one by one:
Code Quality
- All public APIs have type annotations (function signatures and return values)
- All public methods have docstrings (
"""..."""format, including:param/:return/:raises) - Passed
ruff check(no warnings) - Test coverage ≥ 80%
- Passed
pytestall test cases
Compatibility
-
pyproject.tomldeclares the minimum SDK version:dependencies = ["ErisPulse>=x.y.z"] - The module declares the minimum SDK version at runtime in
get_meta()'sModuleMeta(min_sdk_version="x.y.z")(use class attributemin_sdk_versionfor adapters) — if the user's environment SDK is too low, the framework will clearly report an error and skip loading at the loading stage, rather than reporting a hard-to-locate runtime exception - Tested on Python 3.10 / 3.11 / 3.12 / 3.13
- Tested on the target operating system (Windows / Linux / macOS, if applicable)
- No circular import dependencies
Configuration
- If using declarative configuration (
ConfigClass+BaseConfig/BotAccountConfig), configuration fields havedescription(recommended i18n format) anduimetadata - If i18n translation keys are registered, all 5 languages (zh-CN / zh-TW / en / ja / ru) are covered
- Sensitive fields are marked with
secret=True
Documentation
-
README.mdhas installation instructions and basic usage examples -
README.mdexplains the configuration method (configuration file example + environment variables) -
CHANGELOG.mdrecords all changes - Adapter updates platform feature documentation (supported Send types, event types, etc.)
Publishing
-
pyproject.tomlversion number has been updated - Build passed:
python -m build - Pushed to PyPI:
python -m twine upload dist/* - Installation verified:
pip install ErisPulse-xxx && epsdk run
Development Mode Testing
Before the official release, you can test locally using editable mode:
epsdk install -e /path/to/MyModule
# or
pip install -e /path/to/MyModule
Frequently Asked Questions
Must package names start with ErisPulse-?
Not mandatory, but highly recommended. This helps users identify ErisPulse ecosystem packages on PyPI.
Can one package register multiple modules?
Yes. You can configure multiple key-value pairs in entry-points:
[project.entry-points."erispulse.module"]
"ModuleA" = "MyPackage:ModuleA"
"ModuleB" = "MyPackage:ModuleB"
How long does the review take?
Typically within 1-3 working days. You can check the verification status in the "My Modules" section of the Module Store.
Distributing Applications via Docker Images
If your application is not suitable for publication to PyPI (e.g., contains private dependencies or requires a pre-configured environment), you can distribute it via a GitHub Container Registry (GHCR) Docker image, allowing other users to docker pull and start it with one click.
Applicable Scenarios
- You have a complete bot application (module + configuration + entry script) that you want to distribute with one click
- The module/adapter depends on private packages or has a special installation process, making it unsuitable for PyPI
- You want to provide an out-of-the-box deployment solution, lowering the user's usage threshold
1. Create Dockerfile
Based on the ErisPulse official image, you only need to add your module:
FROM erispulse/erispulse:latest
LABEL org.opencontainers.image.title="ErisPulse-MyModule" \
org.opencontainers.image.description="Module description" \
org.opencontainers.image.url="https://github.com/yourname/ErisPulse-MyModule" \
org.opencontainers.image.source="https://github.com/yourname/ErisPulse-MyModule"
COPY pyproject.toml README.md ./
COPY MyModule/ ./MyModule/
RUN uv pip install --system -e .
If your module requires additional system dependencies (e.g., SSH client), add them after RUN uv pip install:
RUN apt-get update && apt-get install -y --no-install-recommends \
openssh-client \
&& rm -rf /var/lib/apt/lists/*
erispulse/erispulse:latestalready includes ErisPulse, ErisPulse-Dashboard, Python runtime, and uv, so there is no need to install them again.
2. Create GitHub Actions Workflow
In .github/workflows/docker-publish.yml, create:
name: Publish Docker Image
on:
workflow_dispatch:
push:
branches:
- main
tags:
- "v*"
permissions:
contents: read
packages: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/my-bot
jobs:
docker-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up QEMU (multi-architecture support)
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
GITHUB_TOKENis automatically provided by GitHub Actions, no need to manually create a key.
3. Trigger Build
Push code or tag to trigger automatically:
# Push to main branch to trigger
git push origin main
# Or tag to trigger
git tag v1.0.0
git push origin v1.0.0
You can also manually trigger it on the GitHub repository's Actions page.
4. Set Image to Public
GHCR images are private by default, you need to set them to Public in GitHub so other users can pull without logging in:
- Go to the repository → Packages → Click the corresponding Package
- Package settings → Danger Zone → Change visibility → Public
5. User Usage
After the build is complete, users can start with docker run in one line:
docker run -d \
--name my-bot \
-p 8000:8000 \
-v $(pwd)/config:/app/config \
-e TZ=Asia/Shanghai \
-e ERISPULSE_DASHBOARD_TOKEN=your-token \
--restart unless-stopped \
ghcr.io/<your-username>/my-bot:latest
Or use docker-compose.yml:
services:
my-bot:
image: ghcr.io/<your-username>/my-bot:latest
container_name: my-bot
ports:
- "8000:8000"
volumes:
- ./config:/app/config
environment:
- TZ=Asia/Shanghai
- ERISPULSE_DASHBOARD_TOKEN=${ERISPULSE_DASHBOARD_TOKEN:-}
restart: unless-stopped
Publish to Docker Hub Simultaneously
Extend the workflow, add Docker Hub login before the login step, and add the Docker Hub address in images:
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: docker.io
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
docker.io/<your-dockerhub-username>/my-bot
ghcr.io/${{ github.repository_owner }}/my-bot
You need to add
DOCKERHUB_USERNAMEandDOCKERHUB_TOKENin the repository Settings → Secrets.
Docker Image vs PyPI Publishing
| Feature | Docker Image (GHCR) | PyPI Publishing |
|---|---|---|
| Distribution Method | docker pull to run instantly |
pip install + manual configuration |
| Scope | Complete application/solution | Single module/adapter |
| Private Dependencies | Native support | Requires private PyPI source |
| Module Store | Not applicable | Can be submitted to the module store |
| Multi-architecture | Supports amd64/arm64 | Architecture-agnostic |
These two methods are not mutually exclusive—you can simultaneously publish modules to the module store via PyPI and provide ready-to-use Docker images via GHCR.