Setting Up a New OVOS Repo

September 1, 2026 · View on GitHub

This guide covers the minimal CI/CD files for a new OVOS Python package. All workflow references use @dev: the active branch of gh-automations. If you are migrating an existing repo that currently uses @master, see Migrating an Existing Repo below.


Required Files

1. version.py

Place this inside your package directory (e.g. my_package/version.py). The block between the marker comments is the only part that automation reads and rewrites:

# The following lines are replaced during the release process.
# START_VERSION_BLOCK
VERSION_MAJOR = 0
VERSION_MINOR = 0
VERSION_BUILD = 1
VERSION_ALPHA = 1
# END_VERSION_BLOCK
__version__ = f"{VERSION_MAJOR}.{VERSION_MINOR}.{VERSION_BUILD}" + (f"a{VERSION_ALPHA}" if VERSION_ALPHA else "")

2. pyproject.toml

Configure dynamic versioning so the package version is always read from version.py at build time:

[project]
name = "my-package"
dynamic = ["version"]
[tool.setuptools.dynamic]
version = {attr = "my_package.version.__version__"}

Do not hard-code the version in pyproject.toml: it must always come from version.py.

3. .github/workflows/conventional-label.yaml

Auto-labels PRs based on conventional commit title prefixes. These labels drive the version bump type.

on:
  pull_request_target:
    types: [opened, edited]
name: conventional-release-labels
jobs:
  label:
    runs-on: ubuntu-latest
    steps:
      - uses: bcoe/conventional-release-labels@v1

Label mapping:

PR title prefixLabel assignedVersion bump
feat:featureminor
fix:fixbuild
BREAKING CHANGE:breakingmajor
anything else(none)alpha only

4. .github/workflows/release_workflow.yml

Triggers on PR merge to dev. Bumps version, publishes alpha, opens release PR.

The publish_alpha job must allow both merged PRs and manual dispatch: the workflow_dispatch clause enables manual reruns from the GitHub Actions UI:

name: Release Alpha and Propose Stable
on:
  workflow_dispatch:
  pull_request:
    types: [closed]
    branches: [dev]
jobs:
  publish_alpha:
    if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch'
    uses: OpenVoiceOS/gh-automations/.github/workflows/publish-alpha.yml@dev
    secrets: inherit
    with:
      branch: 'dev'
      version_file: 'my_package/version.py'  # ← update this path
      update_changelog: true
      publish_prerelease: true
      propose_release: true
      publish_pypi: true        # builds with python -m build, publishes to PyPI
      notify_matrix: true       # posts to OVOS Matrix channel
      changelog_max_issues: 100

5. .github/workflows/publish_stable.yml

Triggers on push to master. Declares stable, tags release, publishes.

The if: github.actor != 'github-actions[bot]' guard is required on the calling job. Without it, the auto-commit pushed by the workflow would retrigger push: master and loop.

name: Stable Release
on:
  push:
    branches: [master]
  workflow_dispatch:
jobs:
  publish_stable:
    if: github.actor != 'github-actions[bot]'
    uses: OpenVoiceOS/gh-automations/.github/workflows/publish-stable.yml@dev
    secrets: inherit
    with:
      branch: 'master'
      version_file: 'my_package/version.py'  # ← update this path
      publish_release: true
      publish_pypi: true        # builds with python -m build, publishes to PyPI
      sync_dev: true            # pushes master → dev after stable release
      notify_matrix: true       # posts to OVOS Matrix channel

Optional Files

build_tests.yml: Build, install, and test across Python versions

name: Run Build Tests
on:
  push:
    branches: [master]
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  build_tests:
    uses: OpenVoiceOS/gh-automations/.github/workflows/build-tests.yml@dev
    secrets: inherit
    with:
      python_versions: '["3.10", "3.11", "3.12"]'
      test_path: 'test/'            # optional: run pytest after install
      package_name: 'my-package'    # needed for channel compatibility check
      version_file: 'my_package/version.py'  # needed for channel compatibility check

To skip test execution and only verify build+install, omit test_path (defaults to empty: build/install only).

opm_check.yml: OPM plugin detection (plugin repos only)

name: OPM Check
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  opm_check:
    uses: OpenVoiceOS/gh-automations/.github/workflows/opm-check.yml@dev
    secrets: inherit
    with:
      plugin_type: auto             # auto-detect from pyproject.toml entry points
      opm_require_found: true       # fail if OPM cannot discover the plugin
      opm_perf_threshold_ms: 500    # warn if import takes longer than 500ms

license_tests.yml: Check dependency licenses

name: Run License Tests
on:
  push:
    branches: [master]
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  license_tests:
    uses: OpenVoiceOS/gh-automations/.github/workflows/license-check.yml@dev
    with:
      install_extras: ''          # e.g. '[extras]'
      system_deps: ''             # e.g. 'portaudio19-dev'
      # exclude_packages: '^(chardet).*'         # per-package exclusions
      # exclude_licenses: '^Mozilla Public License.*'  # MPL allowed by default

downstream.yml: Track downstream dependents

For core packages (e.g. ovos-utils, ovos-bus-client) that many other packages depend on. The report is uploaded as a workflow artifact (no longer committed to the branch).

name: Track Downstream Dependencies
on:
  push:
    branches: [dev]
  schedule:
    - cron: "0 0 * * *"
  workflow_dispatch:
jobs:
  check_downstream:
    uses: OpenVoiceOS/gh-automations/.github/workflows/downstream-check.yml@dev
    secrets: inherit
    with:
      package_name: 'my-package'

pipaudit.yml: CVE scanning

name: Pip Audit
on:
  push:
    branches: [dev, master]
  workflow_dispatch:
jobs:
  pip_audit:
    uses: OpenVoiceOS/gh-automations/.github/workflows/pip-audit.yml@dev
    with:
      install_extras: ''

coverage.yml: Test coverage with PR diff comments

name: Coverage
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  coverage:
    uses: OpenVoiceOS/gh-automations/.github/workflows/coverage.yml@dev
    secrets: inherit
    with:
      coverage_source: 'my_package'   # measure only your own code
      min_coverage: 80                # optional: fail below 80%

coverage_pages.yml: Deploy coverage HTML to GitHub Pages

Use coverage.yml with deploy_pages: true: no separate file needed. Requires Pages enabled in repo settings (Source: Deploy from a branch → gh-pages).

name: Coverage
on:
  push:
    branches: [dev]
  pull_request:
    branches: [dev]
  workflow_dispatch:
permissions:
  contents: write   # required for the gh-pages git push
jobs:
  coverage:
    uses: OpenVoiceOS/gh-automations/.github/workflows/coverage.yml@dev
    secrets: inherit
    with:
      coverage_source: 'my_package'   # measure only your own code
      deploy_pages: true              # push HTML report to gh-pages branch

Prerequisites: Go to repo Settings → Pages → Source → select "Deploy from a branch" → gh-pages.

lint.yml: Ruff + pre-commit

name: Lint
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  lint:
    uses: OpenVoiceOS/gh-automations/.github/workflows/lint.yml@dev
    secrets: inherit
    with:
      ruff: true          # ruff check . (default)
      pre_commit: false   # set true if you have .pre-commit-config.yaml

Results are posted to the OVOS PR Checks comment. The job fails if any tool finds issues.

skill_check.yml: Skill locale + skill.json (skill repos only)

name: Skill Check
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  skill_check:
    uses: OpenVoiceOS/gh-automations/.github/workflows/skill-check.yml@dev
    secrets: inherit

Default skip_if_not_skill: true means this safely no-ops on non-skill repos.

type_check.yml: mypy static type checking

name: Type Check
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  type_check:
    uses: OpenVoiceOS/gh-automations/.github/workflows/type-check.yml@dev
    secrets: inherit
    with:
      mypy_args: 'my_package'    # check only your own code
      fail_on_errors: false      # informational only (default)

Results are posted to the OVOS PR Checks comment. Set fail_on_errors: true to block merges on type errors.

docs_check.yml: Required documentation file check

name: Docs Check
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  docs_check:
    uses: OpenVoiceOS/gh-automations/.github/workflows/docs-check.yml@dev
    secrets: inherit
    with:
      required_files: 'README.md'   # default
      fail_on_missing: false    # informational only (default)

Posts a 📚 Docs section showing which required files are present or missing. Set fail_on_missing: true to fail the job when any listed file is absent.

release_preview.yml: Next-version prediction

name: Release Preview
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  release_preview:
    uses: OpenVoiceOS/gh-automations/.github/workflows/release-preview.yml@dev
    secrets: inherit

repo_health.yml: Required-files check + first-time contributor greeting

name: Repo Health
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  repo_health:
    uses: OpenVoiceOS/gh-automations/.github/workflows/repo-health.yml@dev
    secrets: inherit
    with:
      version_file: 'my_package/version.py'  # if empty, auto-detects

Required GitHub Secrets

Configure these under repo Settings → Secrets and variables → Actions:

SecretUsage
PYPI_TOKENPublish to PyPI (both alpha and stable)
MATRIX_TOKENPost notifications to Matrix chat (only if using notify-matrix.yml)

For organisation repos, these are usually set at the organisation level and inherited.


Configure under repo Settings → Branches:

BranchRules
devRequire PR before merging. Require status checks (build_tests, unit_tests) to pass
masterRequire PR before merging. Require at least 1 approving review. No direct pushes

Allowed Actors

ActorBlocked byReason
github-actions[bot]publish_stable.yml if: guardPrevents loop when the version commit pushes to master
Closed-but-unmerged PRspublish-alpha.yml bump_version job if:Only runs when merged == true

Manual dispatch (workflow_dispatch) is always allowed for both release_workflow.yml and publish_stable.yml.


Migrating an Existing Repo

Migrate codecov → coverage.yml (66 repos affected)

If your repo currently uses codecov/codecov-action in unit_tests.yml, migrate to the self-hosted coverage.yml workflow:

Step 1: Remove the codecov upload step from unit_tests.yml:

# REMOVE this step:
- name: Upload coverage to Codecov
  uses: codecov/codecov-action@v3    # or v2/v4/v5
  with:
    token: ${{ secrets.CODECOV_TOKEN }}

Step 2: Add a new coverage.yml workflow (see Optional Files → coverage.yml):

name: Coverage
on:
  pull_request:
    branches: [dev]
  workflow_dispatch:
jobs:
  coverage:
    uses: OpenVoiceOS/gh-automations/.github/workflows/coverage.yml@dev
    secrets: inherit
    with:
      coverage_source: 'my_package'

Step 3: Remove the CODECOV_TOKEN secret from the repo if it was only used for coverage uploads.

Why migrate? coverage.yml is self-hosted (no external account required), uses only GITHUB_TOKEN, and produces a consistent PR comment format across caller repos.

Note: Do NOT do a bulk migration wave: migrate opportunistically when touching a repo's .github/workflows/ for another reason.

Migrate @master@dev refs

All new repos should reference @dev. If you find @master refs in a repo's caller workflows:

# Before:
uses: OpenVoiceOS/gh-automations/.github/workflows/build-tests.yml@master
# After:
uses: OpenVoiceOS/gh-automations/.github/workflows/build-tests.yml@dev

Do this opportunistically when touching any workflow file in a repo.


← License Whitelist · Home · Repos →