Files
voculinux/CONTRIBUTING.md
T
xavierk 80a3792576
CI / security (pull_request) Failing after 1m25s
CI / lint (pull_request) Failing after 34s
CI / ai-review (pull_request) Successful in 25s
chore: import vocalinux project
Import the vocalinux source tree (tray app, Next.js site in web/,
packaging, installers, docs and tests) on top of the Gitea template
commit. The project README replaces the template README, and the
template CI files (.gitea/workflows/ci.yml, .jscpd.json, CI.md) are kept.
2026-11-06 11:51:44 +05:30

9.7 KiB

Contributing to Vocalinux

Thanks for your interest in contributing. This guide covers setup, style, testing, and pull requests.

Code of conduct

Participation is covered by our Code of Conduct. Be respectful and constructive.

Ways to contribute

Development setup

git clone https://github.com/YOUR-USERNAME/vocalinux.git
cd vocalinux
./install.sh --dev

This installs system dependencies, creates venv/ with an editable install and dev tools, and runs the test suite. See The two environments.

Manual setup

  1. Fork and clone the repository.

  2. Install system dependencies (examples):

    Ubuntu 24.04+:

    sudo apt update
    sudo apt install -y python3-pip python3-gi python3-gi-cairo \
         gir1.2-gtk-3.0 gir1.2-ibus-1.0 libgirepository-2.0-dev libgirepository1.0-dev \
         build-essential pkg-config libcairo2-dev libffi-dev \
        python3-dev portaudio19-dev python3-venv xdotool
    

    Debian 12 (installer environment only):

    sudo apt install -y python3-pip python3-gi python3-gi-cairo \
         gir1.2-gtk-3.0 gir1.2-ibus-1.0 libgirepository1.0-dev libcairo2-dev \
         build-essential pkg-config libffi-dev \
        python3-dev portaudio19-dev python3-venv xdotool
    

    Debian 13+:

    sudo apt install -y python3-pip python3-gi python3-gi-cairo \
         gir1.2-gtk-3.0 gir1.2-ibus-1.0 libgirepository-2.0-dev libcairo2-dev \
         build-essential pkg-config libffi-dev \
        python3-dev portaudio19-dev python3-venv xdotool
    

    Fedora 40+:

    sudo dnf install -y python3-pip python3-gobject gtk3 ibus-devel \
         gobject-introspection-devel glib2-devel python3-devel portaudio-devel \
         cairo-devel cairo-gobject-devel libffi-devel python3-virtualenv pkg-config cmake \
         gcc-c++ make xdotool
    

    AppIndicator (system tray):

    # Older Ubuntu:
    sudo apt install -y gir1.2-appindicator3-0.1
    # Debian 12+ or newer Ubuntu:
    sudo apt install -y gir1.2-ayatanaappindicator3-0.1
    

    macOS (tooling only): brew install portaudio pkg-config; use xcode-select --install if a C compiler is missing. PyGObject/pycairo and their header checks apply only on Linux, which is required to run the desktop app.

  3. Create the environment and install:

    # Requires uv (https://docs.astral.sh/uv/); creates .venv/ with dev + vad extras
    just deps
    

    Missing native build headers are reported with install commands before syncing. For older Linux releases, use the installer environment described below.

  4. Run:

    just run-source-debug
    
  5. Optional pre-commit hooks:

    uv run --no-sync pre-commit install
    

    Hooks are optional. CI runs the same checks.

The two environments

The repository uses two virtual environments on purpose. Do not merge them:

Directory Created by Python Used for
.venv/ just deps (uv) pinned in .python-version dev tooling: pytest, black, mypy, just recipes
venv/ ./install.sh the system Python running the installed app, which needs distro PyGObject
  • On Linux, .venv/ builds the locked PyGObject, requiring glib 2.80+ and the headers above. On Debian 12 or Fedora 39 and older, use ./install.sh --dev, then venv/bin/pytest or venv/bin/python -m vocalinux.main --debug instead.
  • venv/ uses distro PyGObject via --system-site-packages. The installer ignores an activated venv and rebuilds one created by the wrong interpreter. It uses /usr/bin/python3 unless overridden, e.g. SYSTEM_PYTHON=/usr/bin/python3.12 ./install.sh.

just appimage bundles its own Python/PyGObject in the pinned Ubuntu Docker image. For GI failures, check Checking bundled PyGObject after linuxdeploy and the smoke test's path diagnostics; installing python3-gobject on the host won't fix the bundle.

Making changes

Branch naming

git checkout main
git pull origin main
git checkout -b feature/your-feature-name
# or fix/, docs/, refactor/, test/

Never push directly to main. Open a pull request for every change.

Code style

Tool Role
Black Formatting (line length 100)
isort Import sorting (black profile)
flake8 Linting
mypy Type checking (just typecheck)
just format    # black + isort
just lint      # flake8 + black --check + isort --check
just typecheck # mypy src/

Project structure

vocalinux/
├── src/vocalinux/            # Application
│   ├── main.py
│   ├── speech_recognition/   # Engines + command processor
│   ├── text_injection/       # X11 / Wayland injection
│   ├── ui/                   # GTK tray, settings, config
│   └── utils/
├── tests/
├── resources/                # Icons and sounds
├── docs/
├── install.d/                # Installer modules, including generated package data
├── packaging/                # AppImage, AUR, Flatpak
├── scripts/                  # Maintenance tools and distro package-map source
├── snap/                     # Snap recipe
└── web/                      # Marketing site (Next.js)
Task Start here
Voice command src/vocalinux/speech_recognition/command_processor.py
UI src/vocalinux/ui/
Recognition engines src/vocalinux/speech_recognition/recognition_manager.py
Text injection src/vocalinux/text_injection/text_injector.py
Settings / config src/vocalinux/ui/config_manager.py, settings_dialog.py
Installer package names scripts/distro-package-map.yaml

Installer package map

scripts/distro-package-map.yaml is the source of truth for package names, alternatives, and conditional package probes used by install.sh. Do not edit the generated install.d/package_map.sh directly. After changing the YAML, run:

just distro-packages
just distro-packages-check

Commit both the YAML and generated shell module. Package-manager control flow and installation policy remain handwritten in install.d/system_dependencies.sh; user systems never parse the YAML. The remote bootstrap's pre-checkout git installation is the deliberate exception because the generated module is not available yet.

Testing

just test
just test-cov
uv run --extra dev --extra vad --group lint pytest tests/test_command_processor.py
  • Place tests in tests/ as test_*.py
  • Aim for solid coverage on new code (roughly 80%+)
  • Use pytest-mock via the mocker fixture
def test_command_processor_new_line(mocker):
    """Test that 'new line' command returns correct action."""
    processor = CommandProcessor()
    result = processor.process("new line")
    assert result.action == "new_line"

Remote API test server

python scripts/test_remote_server.py
python scripts/test_remote_server.py --port 9000
python scripts/test_remote_server.py --delay 2

Endpoints:

  • whisper.cpp style: http://localhost:8080/inference
  • OpenAI-compatible: http://localhost:8080/v1/audio/transcriptions

In Settings → Speech Model, select Remote API, set the server URL, choose the endpoint format, and use Test Connection.

Pull requests

Automated agents may append three robot emoji (🤖) to the PR title to opt into the agent fast-track merge path when that process is active.

Before you open a PR

  • Style checks pass (just lint, just typecheck)
  • Tests pass (just test)
  • Docs updated when behavior or install steps change
  • Commits use Conventional Commits
type(scope): short description

Longer description if needed.

Fixes #123

Types: feat, fix, docs, style, refactor, test, chore

Examples:

feat(commands): add "select all" voice command
fix(tray): resolve icon not updating on Wayland
docs(readme): update installation instructions

Submit

  1. Push your branch to your fork
  2. Open a PR against main and fill out the template
  3. Link related issues
  4. Wait for CI; address review feedback
  5. Maintainers squash-merge when approved

Releases

Maintainers follow docs/RELEASE_PROCESS.md (version files, docs, website, tag, automated publish). Do not tag releases from feature branches.

Community

License

Contributions are licensed under the GNU Affero General Public License v3.0 (AGPL-3.0), matching the other VocaHQ distribution projects (VocaMac, VocaPhone, VocaGateway). By opening a pull request, you agree that your contribution may be distributed under that license.