Void xbps packaging route #4

Closed
opened 2026-11-05 15:23:04 +00:00 by xavierk · 1 comment
Owner

Part of #1

Question

How should Voculinux be packaged for Void Linux: template shape, CUDA and Python dependency handling, signed personal repository, and tag-driven releases without hand-uploaded assets?

Part of #1 ## Question How should Voculinux be packaged for Void Linux: template shape, CUDA and Python dependency handling, signed personal repository, and tag-driven releases without hand-uploaded assets?
xavierk added the wayfinder:research label 2026-11-05 15:23:04 +00:00
Author
Owner

Void xbps packaging route — research findings

Ticket: Gitea "Void xbps packaging route", part of map "Voculinux port"
(xavierk/voculinux on git.bongbetic.com; tracker conventions in
docs/agents/issue-tracker.md).
Researched 2026-11-05 against primary sources. Local checkout inspected:
packaging/ and scripts/distro-package-map.yaml. No repo files changed.

Naming note: this checkout is still Vocalinux everywhere in code
(pyproject.toml name = "vocalinux", entry points vocalinux /
vocalinux-gui, src/vocalinux/version.py __version__ = "0.18.5") [L1][L2].
"Voculinux" is the Gitea fork name. Every pkgname below is written as
vocalinux; if the fork renames the binary, rename the template directory to
match, because a template must live at srcpkgs/<pkgname>/template with the
directory name equal to pkgname [S3].

Verdict

Dual track, personal repository first. Adopt the established Bongbetic
taema pattern [S10][S11][S12]:

  1. Now — signed personal xbps repository, tag-driven. Keep
    srcpkgs/vocalinux/template (plus two dependency templates, below) in the
    Voculinux repo for xbps-src users, and build release .xbps packages
    with a tools/build-xbps.sh-style xbps-create script in CI inside
    ghcr.io/void-linux/void-glibc / void-musl containers. Sign with
    xbps-rindex, attach packages + signatures + repodata to the GitHub/Gitea
    release, serve the repository from releases/latest/download. Never build
    or upload release assets by hand [S12].
  2. Later, optional — upstream void-packages PRs. Possible but a bigger
    commitment: two missing dependency packages must land first, the app must
    be runtime-tested, and Void prefers submitters with a contribution
    history and software "submitted by someone other than the developer"
    (exceptions possible) [S3]. Do not block the personal repo on this.

No CUDA package. Vulkan + CPU only. Void has no CUDA toolkit package, so
a GGML_CUDA build cannot be produced from Void repositories. Ship
pywhispercpp built with the Vulkan backend (full Vulkan stack exists in
Void), which matches the installer's existing priority
"Vulkan > CUDA fallback > CPU" and its rule that it never installs the CUDA
toolkit [L5].

Three facts drive everything else:

  • The two hard runtime dependencies pywhispercpp (default engine) and
    pynput are not in Void (template probes return HTTP 404, see table in
    §4). Whichever route is chosen, packaging these two comes first.
  • Void python3-PyAudio is 0.2.12_5 [S14], but pyproject.toml requires
    pyaudio>=0.2.13 [L1]. Something must move: update the (orphaned) Void
    template, vendor, or relax the floor after checking why it was raised.
  • Void has no optdepends/recommends. depends is hard. Optional
    engines (Vosk, OpenAI Whisper/torch, Parakeet/sherpa-onnx,
    faster-whisper — none of which are in Void either) cannot be expressed
    like the AUR optdepends list [L3]; they stay separate packages the user
    installs manually, documented in INSTALL.msg/README.

1. Local state (this checkout)

  • packaging/ contains appimage/, aur/, flatpak/, native/
    (.deb/.rpm via nfpm), nix/ — no Void/xbps packaging at all [L7].

  • Void support today is only the install.sh path: docs/DISTRO_COMPATIBILITY.md
    marks Void "Experimental — Untested, manual install required" [L6], and
    install.d/system_dependencies.sh installs the Void inventory with
    xbps-install -Sy [L6].

  • The Void entry in scripts/distro-package-map.yaml:177-184 is the
    authoritative local inventory [L4]:

    void:
      # cairo-devel is needed because the pinned pycairo builds from source.
      # base-devel compiles the pywhispercpp sdist and the evdev/PyAudio sdists.
      system: [python3-pip, python3-gobject, gtk+3, libappindicator-gtk3, gobject-introspection, portaudio-devel, cairo-devel, python3-devel, pkg-config, cmake, base-devel, wget, curl, unzip, shaderc, patchelf, Vulkan-Tools, xclip, xsel, wl-clipboard]
      text_input:
        xdotool: [xdotool]
        wtype: [wtype]
        ydotool: [ydotool]
    

    Two entries look stale against current void-packages (probed 2026-11-05):
    libappindicator-gtk3 has no template (404) — the current package is
    libayatana-appindicator [S13] — and ydotool has no template (404).
    Verify both with xbps-query -Rs on a real Void system before reusing
    this list as depends.

  • Closest local analogues to copy from:

    • AUR packaging/aur/vocalinux/PKGBUILD — canonical release sdist as
      source, python -m build --wheel --no-isolation, python -m installer,
      full depends list, desktop file + scalable icons [L3].
    • packaging/native/nfpm.yaml — "thin" philosophy: interpreter, GTK,
      PyGObject and every distro-packaged Python dep from the distro; only
      pywhispercpp and pynput vendored (under /usr/lib/vocalinux/vendor)
      because Debian/Fedora don't package them [L8]. Void has the same two
      gaps, so the same split applies.
    • packaging/nix/pywhispercpp.nix — a worked example of building
      pywhispercpp without pip: PyPI sdist (vendors whisper.cpp + pybind11),
      GGML_NATIVE=OFF, GGML_VULKAN=ON, shared libs, dontUseCmakeConfigure
      (CMake is driven by setup.py build_ext) [L9].
  • Releases are already tag-driven: .github/workflows/release.yml triggers
    on v* tags, verifies the tag against src/vocalinux/version.py, and
    builds one canonical reproducible wheel/sdist that every publisher
    consumes [L10]. An xbps job fits the same shape.

  • Speech models are not package payload: they are verified against
    digests pinned in src/vocalinux/utils/model_checksums.txt and downloaded
    at first run (AGENTS.md "Speech models" row). The xbps package should not
    bundle models.

2. void-packages template shape

Templates are bash scripts processed by xbps-src; by convention they start
with # Template file for '<pkg>', keep lines under ~80 columns, and define
the mandatory variables pkgname, version, revision, short_desc
(≤72 chars), maintainer ("name "), license (SPDX), homepage,
plus distfiles/checksum for source packages [S1]. AGPL (and MIT/BSD/
ISC/X11/custom) licenses require the license file inside the binary package —
use vlicense LICENSE in post_install() [S1].

For Python software the Manual prescribes python3-module if possible, or
python3-pep517 for PEP 517 projects without setup.py; the pep517 style
provides no backend itself, so the backend goes in hostmakedepends [S1].
The pep517 environment automatically adds python3-build and
python3-installer-bootstrap, builds with
python3 -m build --no-isolation --wheel, and installs with
python3 -m installer --destdir ${DESTDIR} [S2]. That is exactly the AUR
PKGBUILD's build [L3]. Dependency variables split for cross-building:
hostmakedepends (run on host), makedepends (target libraries/headers;
add python3-devel when a compiled extension is built), depends
(runtime), checkdepends [S1]. Setuptools must never fetch missing build
deps at build time — anything it would download belongs in
hostmakedepends [S1]. Void's python3-setuptools is 80.10.2 [S15], which
satisfies this repo's setuptools>=77 build requirement [L1].

Skeleton for the app (illustrative — versions/checksums to fill at build
time; the AUR recipe proves the canonical sdist URL shape [L3]):

# Template file for 'vocalinux'
pkgname=vocalinux
version=0.18.5
revision=1
build_style=python3-pep517
hostmakedepends="python3-setuptools python3-wheel"
depends="python3 python3-gobject python3-cairo gtk+3 libayatana-appindicator
 ibus libnotify python3-numpy python3-requests python3-pysocks python3-psutil
 python3-evdev python3-PyAudio portaudio python3-pynput python3-pywhispercpp
 xdotool wtype wl-clipboard xclip xsel"
short_desc="Free, offline voice dictation for Linux"
maintainer="<name> <email>"
license="AGPL-3.0-only"
homepage="https://github.com/VocaHQ/vocalinux"
distfiles="https://github.com/VocaHQ/vocalinux/releases/download/v${version}/vocalinux-${version}.tar.gz"
checksum=<sha256 of the canonical release sdist>
# GTK/hardware test suite cannot run in the xbps-src chroot:
make_check=no

post_install() {
	vlicense LICENSE
	vinstall vocalinux.desktop 644 usr/share/applications
	vinstall resources/icons/scalable/vocalinux.svg 644 \
		usr/share/icons/hicolor/scalable/apps
}

Notes on the skeleton:

  • Follow the AUR precedent and use the canonical release sdist (same
    bytes as PyPI, checksum-verified), not a git-archive tarball [L3].
    AGENTS.md applies the same rule to AUR publication. For the personal-repo
    track the taema template instead points distfiles at its own tag archive
    plus a vendor tarball [S10]; pick one source of truth and keep
    version/checksum bumped by the release workflow (§6).
  • make_check=no (or extended) must carry a comment explaining why — the
    Manual requires the justification [S1]. Upstream Void additionally
    requires the package to be runtime tested by installing and running
    it, built for at least x86, cross-built e.g. -a armv6l recommended, and
    xlint template clean [S3].
  • Pure-Python app code is architecture-independent, but the old noarch
    value was removed from archs [S1]; leave archs unset for the template
    route. For the xbps-create personal-repo route the staged tree contains
    the compiled pywhispercpp extension, so packages are arch-specific
    (x86_64, x86_64-musl, …) [S11].
  • Triggers (gtk-icon-cache, update-desktopdb, pycompile) fire
    automatically from file placement; no template code needed [S1].
  • An INSTALL.msg is the right place for the notes xbps cannot express as
    dependencies: add the user to the input group for the evdev hotkey
    backend, optional engines are separate packages, models download on first
    run.

Two dependency templates must be written first (same style):

  • python3-pynput — easy. Pure Python PEP 517 package; upstream 1.8.2
    needs six, and on Linux evdev>=1.3 and python-xlib>=0.17 [S16], all
    already in Void (python3-evdev 1.7.1, python3-xlib; verify
    python3-six). Model it on python3-evdev's template [S14].
  • python3-pywhispercpp — the real work. Compiled extension:
    makedepends="python3-devel cmake …" (CMake is invoked by the sdist's
    setup.py build_ext, so do not use the cmake build style — the Nix
    recipe documents the same trap [L9]). Build env, following [L9] and the
    AppImage rules (portable CPU flags; a host-native build SIGILLs on older
    CPUs):
    CMAKE_ARGS="-DBUILD_SHARED_LIBS=ON -DGGML_NATIVE=OFF -DGGML_VULKAN=ON",
    PYWHISPERCPP_VERSION=${version}. Runtime deps per PyPI metadata:
    numpy, requests, tqdm, platformdirs [S17] — all in Void. Pin the
    version to PYWHISPERCPP_VERSION="1.5.0" in install.sh [L5] / uv.lock,
    not the newest PyPI release (1.5.1). Expose the GPU choice as a Void
    build option (build_options="vulkan", default on) so xbps-src
    users can rebuild CPU-only [S1]. Verify with
    pythonImportsCheck-equivalents: pywhispercpp, pywhispercpp.model,
    _pywhispercpp [L9].

3. CUDA and GPU handling

  • No CUDA toolkit exists in Void. Probes of srcpkgs/cuda/template and
    srcpkgs/nvidia-cuda-toolkit/template return 404. The nvidia package
    is repository="nonfree", archs="x86_64", and ships only the driver
    runtime libcuda.so.1 — no nvcc, no cuda_runtime.h, no libcudart
    [S9].
  • This repo's installer requires all three (bin/nvcc,
    include/cuda_runtime.h, libcudart.so*) before attempting a
    GGML_CUDA=1 build, and states "The installer never installs the CUDA
    toolkit" [L5]. A Void binary package therefore cannot be built with CUDA
    from Void repositories alone, on either track. A template
    build_options="cuda" would be dead weight upstream (Void's builders do
    not build restricted packages, and there is no toolkit package to
    depend on [S1]).
  • Vulkan is fully available: Vulkan-Headers, vulkan-loader,
    Vulkan-Tools, shaderc (provides glslc) and glslang all have
    templates (probed 200). The local Void inventory already lists shaderc
    and Vulkan-Tools [L4]. Build libggml-vulkan.so as the shared backend;
    ggml loads backends at runtime, so the same binary still runs CPU-only on
    machines without a Vulkan device. This matches installer priority
    (Vulkan first, including on NVIDIA) [L5].
  • The OpenAI Whisper engine's CUDA path is equally out: no torch in Void
    (404 for python3-torch/python3-pytorch), and this repo pins CPU torch
    for the installer anyway (AGENTS.md). Treat the whisper extra as
    unsupported on Void; document, don't block.
  • NVIDIA users who install the toolkit from NVIDIA's own tarball can
    rebuild python3-pywhispercpp locally with xbps-src and
    GGML_CUDA=1 — an unsupported, documented escape hatch, mirroring how
    install.sh treats a user-provided toolkit [L5].

4. Python dependency handling

Void's interpreter is Python 3.14.8 [S8]; the app requires >=3.11 [L1], so
no version pinning is needed, but every pyproject.toml dependency must map
to a Void binary package (depends), and build-time requirements to
hostmakedepends/makedepends [S1]. Presence probed 2026-11-05 via
raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/<pkg>/template
HTTP status (200 = template exists, 404 = absent):

pyproject.toml requirement [L1] Void package Status
PyGObject (distro gi, never pip) python3-gobject 3.56.2, provides="py3:gi-…" [S13] present
numpy>=1.22,<3 python3-numpy present
requests>=2.28 python3-requests present
PySocks>=1.7.1,<2 python3-pysocks present
psutil>=5.9,<8 python3-psutil present
evdev>=1.6,<2 python3-evdev 1.7.1 (python3-pep517) [S14] present
pyaudio>=0.2.13 python3-PyAudio 0.2.12_5 (python3-module, orphaned) [S14] version too old
pywhispercpp>=1.5,<2 (default engine) — (also no whisper.cpp/ggml) absent — package it
pynput>=1.7.6,<2 — (its deps python3-evdev, python3-xlib present) absent — package it
extra vad: onnxruntime>=1.16 — absent (optional)
extra parakeet: sherpa-onnx — absent (optional)
extra faster_whisper (+ ctranslate2) — absent (optional)
extra vosk — absent (optional)
extra whisper: openai-whisper, torch — absent (optional)

System (non-Python) side, from the local Void inventory [L4] cross-checked
the same way: present — gtk+3, gobject-introspection, portaudio
(+-devel), python3-cairo, ibus, libnotify, libayatana-appindicator,
gtk-layer-shell, xdotool, wtype, wl-clipboard, xclip, xsel,
shaderc, Vulkan-Tools, cmake, python3-build, python3-installer,
python3-setuptools, python3-wheel, python3-tqdm,
python3-platformdirs. Absent — libappindicator(-gtk3) (use
libayatana-appindicator), ydotool.

Handling rules that follow:

  1. No pip at build or install time. The template route forbids fetched
    build deps [S1]; the xbps-create route stages files built in a Void
    container from Void packages + the two source-built deps [S11]. The
    --system-site-packages venv dance in install.sh (AGENTS.md) does not
    apply to a system package: gi comes from python3-gobject directly.
  2. Fix the PyAudio gap deliberately. Options, in order: (a) update
    Void's orphaned python3-PyAudio to 0.2.14 — also the contribution
    history Void prefers before new-package submissions [S3]; (b) for the
    personal repo, build python3-PyAudio 0.2.14 in-repo; (c) relax the
    >=0.2.13 floor only after finding why it was raised. Do not silently
    set noverifypydeps to hide it.
  3. musl is a first-class Void target. Glibc manylinux wheels are
    unusable on x86_64-musl. The template route gets musl builds for free
    (Void builds every template per-libc); the xbps-create route must
    build pywhispercpp/pynput/evdev/PyAudio from sdist inside the
    musl container and must avoid Node-based Actions steps there [S10].
  4. Byte-compilation and shebangs are automatic via the pycompile
    trigger for files under usr/lib/pythonX.Y/site-packages; use
    pycompile_module="vocalinux" only if the default guesses wrong [S1].
  5. Version-locking policy differs from install.sh. The installer
    consumes hash-pinned uv.lock exports (AGENTS.md); a Void package
    deliberately floats on Void's package versions within the
    pyproject.toml ranges. Accept that, and let the release smoke test
    (§6) catch drift — e.g. Void's Python moving from 3.14 to 3.15 rebuilds
    every python3-* package's extension paths.

5. Signed personal repository

Primary-source mechanics, Void Handbook + xbps-rindex(1):

  • "Remote repositories must be signed"; xbps-install refuses unsigned
    remote packages. Local repositories need no signature [S5][S6].

  • The signing key is a PEM-encoded RSA key (ssh-keygen -t rsa -b 4096 -m PEM
    or openssl genrsa … 4096) [S5]. One-time repository initialisation
    embeds the public half: xbps-rindex --privkey private.pem --sign --signedby "Name <email>" /path/to/repo; each package is then signed
    individually: xbps-rindex --privkey private.pem --sign-pkg repo/*.xbps
    (-S short form). "Future packages will not be automatically signed" —
    signing is a per-release CI step, not a one-off [S5][S7].

  • Users add the repo with one line in /etc/xbps.d/*.conf:
    repository=<URL> [S6].

  • Verified working shape (taema): CI builds per-arch .xbps, then a sign
    job runs XBPS_ARCH=<arch> xbps-rindex -a <pkg>.xbps, xbps-rindex --privkey "$key" --signedby "Bongbetic <…>" -s . and xbps-rindex --privkey "$key" -S <pkg>.xbps per arch, and uploads packages,
    per-package .sig2 signatures and signed <arch>-repodata to the
    release [S10][S12].

  • Serving trick: point the repository URL at
    https://github.com/<owner>/<repo>/releases/latest/download. xbps reads
    repodata from the newest release, so every release must carry the full
    repodata
    ; no gh-pages branch needed [S12]. User install is then:

    echo 'repository=https://github.com/<owner>/<repo>/releases/latest/download' \
      | sudo tee /etc/xbps.d/20-vocalinux.conf
    sudo xbps-install -S vocalinux
    
  • Key hygiene (standing Bongbetic practice): RSA 4096 key, mode 600, never
    committed, stored as the Actions secret XBPS_PRIVKEY; publish the key
    fingerprint in the README so users can check it at first sync; reuse the
    existing taema key so users accept one fingerprint [S12]. (Fingerprint
    value itself lives in personal memory release-xbps.md [S12].)

  • Void's own caveat to repeat in the README: "The Void project does not
    support any third-party package repositories" — users opt in knowingly
    [S6].

Architecture matrix: start with x86_64 + x86_64-musl only. That is
what the current taema workflow actually builds ("Packages are built only
for x86_64 glibc and x86_64 musl", with a per-libc container matrix) [S10][S11].
Personal memory still describes a 9-arch release [S12]; treat that as stale
— adding aarch64 later means cross/QEMU builds of the pywhispercpp
extension plus a native smoke test, a separate ticket.

6. Tag-driven releases

Combine this repo's existing release discipline [L10] with taema's [S10][S12]:

  1. Bump __version__ in src/vocalinux/version.py (the version source of
    truth, AGENTS.md), commit, push a tag. The workflow fails unless the
    tag equals the source version
    (taema uses <name>-vX.Y.Z and a sed
    check against __version__; this repo's release.yml does the same for
    v*) [S10][L10]. For the fork, prefer voculinux-vX.Y.Z so xbps
    releases never collide with upstream-style v* tags — decide once, in
    the map ticket. Pushing commits/tags to GitHub needs the user's explicit
    OK each time [S12].
  2. Build jobs run in ghcr.io/void-linux/void-glibc / void-musl: install
    build deps with xbps-install, run tests as a non-root user, run
    tools/build-xbps.sh (stage → xbps-create -A <arch> -n <pkg>-<ver>_1 -D "<depends>" … → xbps-rindex -a) [S10][S11]. For this app the stage
    step installs the canonical wheel with python -m installer --destdir="$stage", adds the two source-built deps (or depends on
    separately built python3-pynput/python3-pywhispercpp .xbps in the
    same repo — cleaner, and what the template route needs anyway), the
    desktop file, icons and license [L3][L8]. Add an import smoke inside the
    container (vocalinux --version, import pywhispercpp.model), mirroring
    packaging/native/smoke-test.sh.
  3. Sign job (glibc container): index, sign repo, sign packages, upload
    all assets (packages, .sig2, every <arch>-repodata) to the draft
    release, publish [S10]. If XBPS_PRIVKEY is unset, fail rather than
    publish unsigned (taema degrades to package-only; do not copy that —
    an unsigned remote repo is uninstallable [S6]).
  4. Post-release job bumps version and checksum in
    srcpkgs/vocalinux/template (and README download names) and commits to
    main [S10][S12], so xbps-src users always build the released bytes.
  5. Never build or upload release assets by hand [S12].

7. Risks and open questions

  • Name. vocalinux vs voculinux for pkgname, repo file
    (20-vocalinux.conf), tags (v* vs voculinux-v*), and release host
    (GitHub VocaHQ/vocalinux vs Gitea xavierk/voculinux). Gitea releases
    also expose a "latest download" style URL, but the verified taema pattern
    is GitHub [S10][S12]. One decision in the map ticket settles all four.
  • PyAudio floor (>=0.2.13 vs Void 0.2.12) — find the commit that
    raised it before relaxing anything (§4 rule 2).
  • Stale local Void inventory: libappindicator-gtk3 and ydotool in
    [L4] do not resolve as templates today. Without ydotool, Wayland text
    injection falls back to IBus/RemoteDesktop portal/wtype — say so in
    INSTALL.msg; packaging ydotool is a possible follow-up ticket.
  • No systemd on Void (runit). Anything in the app assuming a user
    systemd service (e.g. per-user ydotool.service, autostart units) needs
    the XDG-autostart path instead. Confirm during the runtime test [S3].
  • Upstream acceptance is uncertain: package requirements (system-wide,
    compiled, or required-by-another), mature release history, non-author
    submitter preference [S3]. The app arguably meets "system + compiled
    (via pywhispercpp)", but budget it as a multi-PR campaign
    (PyAudio update → python3-pynput → python3-pywhispercpp → app), each
    xlint-clean and runtime-tested [S3].
  • Update checker: the app self-checks GitHub releases; under xbps,
    updates should arrive via xbps-install -Su [S10]. Decide whether the
    package patches out or documents the built-in checker (packaging
    convention only — not verified against app code in this research).

8. Implementation checklist (ordered)

  1. Verify inventory on a real Void x86_64 (glibc) VM/container:
    xbps-query -Rs each [L4] entry; confirm libayatana-appindicator
    typelib name and python3-six.
  2. Write srcpkgs/python3-pynput/template, srcpkgs/python3-pywhispercpp/template
    (Vulkan build option, GGML_NATIVE=OFF), srcpkgs/vocalinux/template +
    INSTALL.msg; xlint all three; ./xbps-src pkg + runtime test.
  3. Resolve PyAudio (update template locally to 0.2.14 first).
  4. Add tools/build-xbps.sh (podman-friendly: runs inside
    ghcr.io/void-linux/void-{glibc,musl}), staging the canonical wheel.
  5. Add the tag workflow (voculinux-v* or v* per §7): build matrix →
    sign with XBPS_PRIVKEY → publish release with full repodata →
    template-checksum bump commit.
  6. README section: repo URL, fingerprint, xbps-install -S line,
    third-party-repo caveat [S6], CUDA/Vulkan note.
  7. Smoke on real Void hardware: first-run model download, push-to-talk
    (evdev + input group), tray icon, Wayland + X11 injection.
  8. (Optional, later) Upstream PR campaign per §7; aarch64 builds.

Sources

Primary (Void / upstream):

Precedent (Bongbetic, first-party):

Local checkout:

Method note: template presence (§4) was probed by HTTP status of each
srcpkgs/<pkg>/template on void-packages master, 2026-11-05; a 404 means
no template under that exact name (subpackages of another source package
would not appear). Re-verify with xbps-query -Rs before implementation.

# Void xbps packaging route — research findings Ticket: Gitea "Void xbps packaging route", part of map "Voculinux port" (`xavierk/voculinux` on `git.bongbetic.com`; tracker conventions in [docs/agents/issue-tracker.md](/media/Toto/Documents/bongbetic/vocalinux/docs/agents/issue-tracker.md)). Researched 2026-11-05 against primary sources. Local checkout inspected: `packaging/` and `scripts/distro-package-map.yaml`. No repo files changed. Naming note: this checkout is still **Vocalinux** everywhere in code (`pyproject.toml` `name = "vocalinux"`, entry points `vocalinux` / `vocalinux-gui`, `src/vocalinux/version.py` `__version__ = "0.18.5"`) [L1][L2]. "Voculinux" is the Gitea fork name. Every `pkgname` below is written as `vocalinux`; if the fork renames the binary, rename the template directory to match, because a template must live at `srcpkgs/<pkgname>/template` with the directory name equal to `pkgname` [S3]. ## Verdict **Dual track, personal repository first.** Adopt the established Bongbetic taema pattern [S10][S11][S12]: 1. **Now — signed personal xbps repository, tag-driven.** Keep `srcpkgs/vocalinux/template` (plus two dependency templates, below) in the Voculinux repo for `xbps-src` users, and build release `.xbps` packages with a `tools/build-xbps.sh`-style `xbps-create` script in CI inside `ghcr.io/void-linux/void-glibc` / `void-musl` containers. Sign with `xbps-rindex`, attach packages + signatures + repodata to the GitHub/Gitea release, serve the repository from `releases/latest/download`. Never build or upload release assets by hand [S12]. 2. **Later, optional — upstream `void-packages` PRs.** Possible but a bigger commitment: two missing dependency packages must land first, the app must be runtime-tested, and Void prefers submitters with a contribution history and software "submitted by someone other than the developer" (exceptions possible) [S3]. Do not block the personal repo on this. **No CUDA package. Vulkan + CPU only.** Void has no CUDA toolkit package, so a `GGML_CUDA` build cannot be produced from Void repositories. Ship pywhispercpp built with the Vulkan backend (full Vulkan stack exists in Void), which matches the installer's existing priority "Vulkan > CUDA fallback > CPU" and its rule that it never installs the CUDA toolkit [L5]. Three facts drive everything else: - The two hard runtime dependencies `pywhispercpp` (default engine) and `pynput` are **not in Void** (template probes return HTTP 404, see table in §4). Whichever route is chosen, packaging these two comes first. - Void `python3-PyAudio` is `0.2.12_5` [S14], but `pyproject.toml` requires `pyaudio>=0.2.13` [L1]. Something must move: update the (orphaned) Void template, vendor, or relax the floor after checking why it was raised. - Void has **no `optdepends`/recommends**. `depends` is hard. Optional engines (Vosk, OpenAI Whisper/torch, Parakeet/sherpa-onnx, faster-whisper — none of which are in Void either) cannot be expressed like the AUR `optdepends` list [L3]; they stay separate packages the user installs manually, documented in `INSTALL.msg`/README. ## 1. Local state (this checkout) - `packaging/` contains `appimage/`, `aur/`, `flatpak/`, `native/` (.deb/.rpm via nfpm), `nix/` — **no Void/xbps packaging at all** [L7]. - Void support today is only the `install.sh` path: `docs/DISTRO_COMPATIBILITY.md` marks Void "Experimental — Untested, manual install required" [L6], and `install.d/system_dependencies.sh` installs the Void inventory with `xbps-install -Sy` [L6]. - The Void entry in `scripts/distro-package-map.yaml:177-184` is the authoritative local inventory [L4]: ```yaml void: # cairo-devel is needed because the pinned pycairo builds from source. # base-devel compiles the pywhispercpp sdist and the evdev/PyAudio sdists. system: [python3-pip, python3-gobject, gtk+3, libappindicator-gtk3, gobject-introspection, portaudio-devel, cairo-devel, python3-devel, pkg-config, cmake, base-devel, wget, curl, unzip, shaderc, patchelf, Vulkan-Tools, xclip, xsel, wl-clipboard] text_input: xdotool: [xdotool] wtype: [wtype] ydotool: [ydotool] ``` Two entries look stale against current void-packages (probed 2026-11-05): `libappindicator-gtk3` has no template (404) — the current package is `libayatana-appindicator` [S13] — and `ydotool` has no template (404). Verify both with `xbps-query -Rs` on a real Void system before reusing this list as `depends`. - Closest local analogues to copy from: - AUR `packaging/aur/vocalinux/PKGBUILD` — canonical release sdist as source, `python -m build --wheel --no-isolation`, `python -m installer`, full `depends` list, desktop file + scalable icons [L3]. - `packaging/native/nfpm.yaml` — "thin" philosophy: interpreter, GTK, PyGObject and every distro-packaged Python dep from the distro; only `pywhispercpp` and `pynput` vendored (under `/usr/lib/vocalinux/vendor`) because Debian/Fedora don't package them [L8]. Void has the same two gaps, so the same split applies. - `packaging/nix/pywhispercpp.nix` — a worked example of building pywhispercpp without pip: PyPI sdist (vendors whisper.cpp + pybind11), `GGML_NATIVE=OFF`, `GGML_VULKAN=ON`, shared libs, `dontUseCmakeConfigure` (CMake is driven by `setup.py build_ext`) [L9]. - Releases are already tag-driven: `.github/workflows/release.yml` triggers on `v*` tags, verifies the tag against `src/vocalinux/version.py`, and builds one canonical reproducible wheel/sdist that every publisher consumes [L10]. An xbps job fits the same shape. - Speech models are **not** package payload: they are verified against digests pinned in `src/vocalinux/utils/model_checksums.txt` and downloaded at first run (AGENTS.md "Speech models" row). The xbps package should not bundle models. ## 2. void-packages template shape Templates are bash scripts processed by `xbps-src`; by convention they start with `# Template file for '<pkg>'`, keep lines under ~80 columns, and define the mandatory variables `pkgname`, `version`, `revision`, `short_desc` (≤72 chars), `maintainer` ("name <email>"), `license` (SPDX), `homepage`, plus `distfiles`/`checksum` for source packages [S1]. `AGPL` (and MIT/BSD/ ISC/X11/custom) licenses require the license file inside the binary package — use `vlicense LICENSE` in `post_install()` [S1]. For Python software the Manual prescribes `python3-module` if possible, or `python3-pep517` for PEP 517 projects without `setup.py`; the pep517 style provides no backend itself, so the backend goes in `hostmakedepends` [S1]. The pep517 environment automatically adds `python3-build` and `python3-installer-bootstrap`, builds with `python3 -m build --no-isolation --wheel`, and installs with `python3 -m installer --destdir ${DESTDIR}` [S2]. That is exactly the AUR PKGBUILD's build [L3]. Dependency variables split for cross-building: `hostmakedepends` (run on host), `makedepends` (target libraries/headers; add `python3-devel` when a compiled extension is built), `depends` (runtime), `checkdepends` [S1]. Setuptools must never fetch missing build deps at build time — anything it would download belongs in `hostmakedepends` [S1]. Void's `python3-setuptools` is 80.10.2 [S15], which satisfies this repo's `setuptools>=77` build requirement [L1]. Skeleton for the app (illustrative — versions/checksums to fill at build time; the AUR recipe proves the canonical sdist URL shape [L3]): ```bash # Template file for 'vocalinux' pkgname=vocalinux version=0.18.5 revision=1 build_style=python3-pep517 hostmakedepends="python3-setuptools python3-wheel" depends="python3 python3-gobject python3-cairo gtk+3 libayatana-appindicator ibus libnotify python3-numpy python3-requests python3-pysocks python3-psutil python3-evdev python3-PyAudio portaudio python3-pynput python3-pywhispercpp xdotool wtype wl-clipboard xclip xsel" short_desc="Free, offline voice dictation for Linux" maintainer="<name> <email>" license="AGPL-3.0-only" homepage="https://github.com/VocaHQ/vocalinux" distfiles="https://github.com/VocaHQ/vocalinux/releases/download/v${version}/vocalinux-${version}.tar.gz" checksum=<sha256 of the canonical release sdist> # GTK/hardware test suite cannot run in the xbps-src chroot: make_check=no post_install() { vlicense LICENSE vinstall vocalinux.desktop 644 usr/share/applications vinstall resources/icons/scalable/vocalinux.svg 644 \ usr/share/icons/hicolor/scalable/apps } ``` Notes on the skeleton: - Follow the AUR precedent and use the **canonical release sdist** (same bytes as PyPI, checksum-verified), not a git-archive tarball [L3]. AGENTS.md applies the same rule to AUR publication. For the personal-repo track the taema template instead points `distfiles` at its own tag archive plus a vendor tarball [S10]; pick one source of truth and keep `version`/`checksum` bumped by the release workflow (§6). - `make_check=no` (or `extended`) must carry a comment explaining why — the Manual requires the justification [S1]. Upstream Void additionally requires the package to be **runtime tested** by installing and running it, built for at least x86, cross-built e.g. `-a armv6l` recommended, and `xlint template` clean [S3]. - Pure-Python app code is architecture-independent, but the old `noarch` value was removed from `archs` [S1]; leave `archs` unset for the template route. For the `xbps-create` personal-repo route the staged tree contains the compiled `pywhispercpp` extension, so packages are arch-specific (`x86_64`, `x86_64-musl`, …) [S11]. - Triggers (`gtk-icon-cache`, `update-desktopdb`, `pycompile`) fire automatically from file placement; no template code needed [S1]. - An `INSTALL.msg` is the right place for the notes xbps cannot express as dependencies: add the user to the `input` group for the evdev hotkey backend, optional engines are separate packages, models download on first run. Two dependency templates must be written first (same style): - **`python3-pynput`** — easy. Pure Python PEP 517 package; upstream 1.8.2 needs `six`, and on Linux `evdev>=1.3` and `python-xlib>=0.17` [S16], all already in Void (`python3-evdev` 1.7.1, `python3-xlib`; verify `python3-six`). Model it on `python3-evdev`'s template [S14]. - **`python3-pywhispercpp`** — the real work. Compiled extension: `makedepends="python3-devel cmake …"` (CMake is invoked by the sdist's `setup.py build_ext`, so do not use the `cmake` build style — the Nix recipe documents the same trap [L9]). Build env, following [L9] and the AppImage rules (portable CPU flags; a host-native build SIGILLs on older CPUs): `CMAKE_ARGS="-DBUILD_SHARED_LIBS=ON -DGGML_NATIVE=OFF -DGGML_VULKAN=ON"`, `PYWHISPERCPP_VERSION=${version}`. Runtime deps per PyPI metadata: `numpy`, `requests`, `tqdm`, `platformdirs` [S17] — all in Void. Pin the version to `PYWHISPERCPP_VERSION="1.5.0"` in `install.sh` [L5] / `uv.lock`, not the newest PyPI release (1.5.1). Expose the GPU choice as a Void **build option** (`build_options="vulkan"`, default on) so `xbps-src` users can rebuild CPU-only [S1]. Verify with `pythonImportsCheck`-equivalents: `pywhispercpp`, `pywhispercpp.model`, `_pywhispercpp` [L9]. ## 3. CUDA and GPU handling - **No CUDA toolkit exists in Void.** Probes of `srcpkgs/cuda/template` and `srcpkgs/nvidia-cuda-toolkit/template` return 404. The `nvidia` package is `repository="nonfree"`, `archs="x86_64"`, and ships only the driver runtime `libcuda.so.1` — no `nvcc`, no `cuda_runtime.h`, no `libcudart` [S9]. - This repo's installer requires all three (`bin/nvcc`, `include/cuda_runtime.h`, `libcudart.so*`) before attempting a `GGML_CUDA=1` build, and states "The installer never installs the CUDA toolkit" [L5]. A Void binary package therefore cannot be built with CUDA from Void repositories alone, on either track. A template `build_options="cuda"` would be dead weight upstream (Void's builders do not build `restricted` packages, and there is no toolkit package to depend on [S1]). - **Vulkan is fully available**: `Vulkan-Headers`, `vulkan-loader`, `Vulkan-Tools`, `shaderc` (provides `glslc`) and `glslang` all have templates (probed 200). The local Void inventory already lists `shaderc` and `Vulkan-Tools` [L4]. Build `libggml-vulkan.so` as the shared backend; ggml loads backends at runtime, so the same binary still runs CPU-only on machines without a Vulkan device. This matches installer priority (Vulkan first, including on NVIDIA) [L5]. - The OpenAI Whisper engine's CUDA path is equally out: no `torch` in Void (404 for `python3-torch`/`python3-pytorch`), and this repo pins CPU torch for the installer anyway (AGENTS.md). Treat the `whisper` extra as unsupported on Void; document, don't block. - NVIDIA users who install the toolkit from NVIDIA's own tarball can rebuild `python3-pywhispercpp` locally with `xbps-src` and `GGML_CUDA=1` — an unsupported, documented escape hatch, mirroring how `install.sh` treats a user-provided toolkit [L5]. ## 4. Python dependency handling Void's interpreter is Python 3.14.8 [S8]; the app requires `>=3.11` [L1], so no version pinning is needed, but every `pyproject.toml` dependency must map to a Void binary package (`depends`), and build-time requirements to `hostmakedepends`/`makedepends` [S1]. Presence probed 2026-11-05 via `raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/<pkg>/template` HTTP status (200 = template exists, 404 = absent): | `pyproject.toml` requirement [L1] | Void package | Status | |---|---|---| | `PyGObject` (distro `gi`, never pip) | `python3-gobject` 3.56.2, `provides="py3:gi-…"` [S13] | present | | `numpy>=1.22,<3` | `python3-numpy` | present | | `requests>=2.28` | `python3-requests` | present | | `PySocks>=1.7.1,<2` | `python3-pysocks` | present | | `psutil>=5.9,<8` | `python3-psutil` | present | | `evdev>=1.6,<2` | `python3-evdev` 1.7.1 (`python3-pep517`) [S14] | present | | `pyaudio>=0.2.13` | `python3-PyAudio` **0.2.12_5** (`python3-module`, orphaned) [S14] | **version too old** | | `pywhispercpp>=1.5,<2` (default engine) | — (also no `whisper.cpp`/`ggml`) | **absent — package it** | | `pynput>=1.7.6,<2` | — (its deps `python3-evdev`, `python3-xlib` present) | **absent — package it** | | extra `vad`: `onnxruntime>=1.16` | — | absent (optional) | | extra `parakeet`: `sherpa-onnx` | — | absent (optional) | | extra `faster_whisper` (+ `ctranslate2`) | — | absent (optional) | | extra `vosk` | — | absent (optional) | | extra `whisper`: `openai-whisper`, `torch` | — | absent (optional) | System (non-Python) side, from the local Void inventory [L4] cross-checked the same way: present — `gtk+3`, `gobject-introspection`, `portaudio` (+`-devel`), `python3-cairo`, `ibus`, `libnotify`, `libayatana-appindicator`, `gtk-layer-shell`, `xdotool`, `wtype`, `wl-clipboard`, `xclip`, `xsel`, `shaderc`, `Vulkan-Tools`, `cmake`, `python3-build`, `python3-installer`, `python3-setuptools`, `python3-wheel`, `python3-tqdm`, `python3-platformdirs`. Absent — `libappindicator(-gtk3)` (use `libayatana-appindicator`), `ydotool`. Handling rules that follow: 1. **No pip at build or install time.** The template route forbids fetched build deps [S1]; the `xbps-create` route stages files built in a Void container from Void packages + the two source-built deps [S11]. The `--system-site-packages` venv dance in `install.sh` (AGENTS.md) does not apply to a system package: `gi` comes from `python3-gobject` directly. 2. **Fix the PyAudio gap deliberately.** Options, in order: (a) update Void's orphaned `python3-PyAudio` to 0.2.14 — also the contribution history Void prefers before new-package submissions [S3]; (b) for the personal repo, build `python3-PyAudio` 0.2.14 in-repo; (c) relax the `>=0.2.13` floor only after finding why it was raised. Do not silently set `noverifypydeps` to hide it. 3. **musl is a first-class Void target.** Glibc manylinux wheels are unusable on `x86_64-musl`. The template route gets musl builds for free (Void builds every template per-libc); the `xbps-create` route must build `pywhispercpp`/`pynput`/`evdev`/`PyAudio` from sdist inside the musl container and must avoid Node-based Actions steps there [S10]. 4. **Byte-compilation and shebangs are automatic** via the `pycompile` trigger for files under `usr/lib/pythonX.Y/site-packages`; use `pycompile_module="vocalinux"` only if the default guesses wrong [S1]. 5. **Version-locking policy differs from `install.sh`.** The installer consumes hash-pinned `uv.lock` exports (AGENTS.md); a Void package deliberately floats on Void's package versions within the `pyproject.toml` ranges. Accept that, and let the release smoke test (§6) catch drift — e.g. Void's Python moving from 3.14 to 3.15 rebuilds every `python3-*` package's extension paths. ## 5. Signed personal repository Primary-source mechanics, Void Handbook + `xbps-rindex(1)`: - "Remote repositories **must** be signed"; `xbps-install` refuses unsigned remote packages. Local repositories need no signature [S5][S6]. - The signing key is a **PEM-encoded RSA key** (`ssh-keygen -t rsa -b 4096 -m PEM` or `openssl genrsa … 4096`) [S5]. One-time repository initialisation embeds the public half: `xbps-rindex --privkey private.pem --sign --signedby "Name <email>" /path/to/repo`; each package is then signed individually: `xbps-rindex --privkey private.pem --sign-pkg repo/*.xbps` (`-S` short form). "Future packages will not be automatically signed" — signing is a per-release CI step, not a one-off [S5][S7]. - Users add the repo with one line in `/etc/xbps.d/*.conf`: `repository=<URL>` [S6]. - Verified working shape (taema): CI builds per-arch `.xbps`, then a sign job runs `XBPS_ARCH=<arch> xbps-rindex -a <pkg>.xbps`, `xbps-rindex --privkey "$key" --signedby "Bongbetic <…>" -s .` and `xbps-rindex --privkey "$key" -S <pkg>.xbps` per arch, and uploads packages, per-package `.sig2` signatures and signed `<arch>-repodata` to the release [S10][S12]. - Serving trick: point the repository URL at `https://github.com/<owner>/<repo>/releases/latest/download`. xbps reads repodata from the newest release, so **every release must carry the full repodata**; no gh-pages branch needed [S12]. User install is then: ```bash echo 'repository=https://github.com/<owner>/<repo>/releases/latest/download' \ | sudo tee /etc/xbps.d/20-vocalinux.conf sudo xbps-install -S vocalinux ``` - Key hygiene (standing Bongbetic practice): RSA 4096 key, mode 600, never committed, stored as the Actions secret `XBPS_PRIVKEY`; publish the key fingerprint in the README so users can check it at first sync; reuse the existing taema key so users accept one fingerprint [S12]. (Fingerprint value itself lives in personal memory `release-xbps.md` [S12].) - Void's own caveat to repeat in the README: "The Void project does not support *any* third-party package repositories" — users opt in knowingly [S6]. Architecture matrix: start with **`x86_64` + `x86_64-musl` only**. That is what the current taema workflow actually builds ("Packages are built only for x86_64 glibc and x86_64 musl", with a per-libc container matrix) [S10][S11]. Personal memory still describes a 9-arch release [S12]; treat that as stale — adding `aarch64` later means cross/QEMU builds of the `pywhispercpp` extension plus a native smoke test, a separate ticket. ## 6. Tag-driven releases Combine this repo's existing release discipline [L10] with taema's [S10][S12]: 1. Bump `__version__` in `src/vocalinux/version.py` (the version source of truth, AGENTS.md), commit, push a tag. The workflow **fails unless the tag equals the source version** (taema uses `<name>-vX.Y.Z` and a `sed` check against `__version__`; this repo's `release.yml` does the same for `v*`) [S10][L10]. For the fork, prefer `voculinux-vX.Y.Z` so xbps releases never collide with upstream-style `v*` tags — decide once, in the map ticket. Pushing commits/tags to GitHub needs the user's explicit OK each time [S12]. 2. Build jobs run in `ghcr.io/void-linux/void-glibc` / `void-musl`: install build deps with `xbps-install`, run tests as a non-root user, run `tools/build-xbps.sh` (stage → `xbps-create -A <arch> -n <pkg>-<ver>_1 -D "<depends>" …` → `xbps-rindex -a`) [S10][S11]. For this app the stage step installs the canonical wheel with `python -m installer --destdir="$stage"`, adds the two source-built deps (or `depends` on separately built `python3-pynput`/`python3-pywhispercpp` `.xbps` in the same repo — cleaner, and what the template route needs anyway), the desktop file, icons and license [L3][L8]. Add an import smoke inside the container (`vocalinux --version`, `import pywhispercpp.model`), mirroring `packaging/native/smoke-test.sh`. 3. Sign job (glibc container): index, sign repo, sign packages, upload **all** assets (packages, `.sig2`, every `<arch>-repodata`) to the draft release, publish [S10]. If `XBPS_PRIVKEY` is unset, fail rather than publish unsigned (taema degrades to package-only; do not copy that — an unsigned remote repo is uninstallable [S6]). 4. Post-release job bumps `version` and `checksum` in `srcpkgs/vocalinux/template` (and README download names) and commits to `main` [S10][S12], so `xbps-src` users always build the released bytes. 5. Never build or upload release assets by hand [S12]. ## 7. Risks and open questions - **Name.** `vocalinux` vs `voculinux` for `pkgname`, repo file (`20-vocalinux.conf`), tags (`v*` vs `voculinux-v*`), and release host (GitHub `VocaHQ/vocalinux` vs Gitea `xavierk/voculinux`). Gitea releases also expose a "latest download" style URL, but the verified taema pattern is GitHub [S10][S12]. One decision in the map ticket settles all four. - **PyAudio floor** (`>=0.2.13` vs Void 0.2.12) — find the commit that raised it before relaxing anything (§4 rule 2). - **Stale local Void inventory**: `libappindicator-gtk3` and `ydotool` in [L4] do not resolve as templates today. Without `ydotool`, Wayland text injection falls back to IBus/RemoteDesktop portal/`wtype` — say so in `INSTALL.msg`; packaging `ydotool` is a possible follow-up ticket. - **No systemd on Void** (runit). Anything in the app assuming a user systemd service (e.g. per-user `ydotool.service`, autostart units) needs the XDG-autostart path instead. Confirm during the runtime test [S3]. - **Upstream acceptance is uncertain**: package requirements (system-wide, compiled, or required-by-another), mature release history, non-author submitter preference [S3]. The app arguably meets "system + compiled (via pywhispercpp)", but budget it as a multi-PR campaign (PyAudio update → `python3-pynput` → `python3-pywhispercpp` → app), each `xlint`-clean and runtime-tested [S3]. - **Update checker**: the app self-checks GitHub releases; under xbps, updates should arrive via `xbps-install -Su` [S10]. Decide whether the package patches out or documents the built-in checker (packaging convention only — not verified against app code in this research). ## 8. Implementation checklist (ordered) 1. Verify inventory on a real Void x86_64 (glibc) VM/container: `xbps-query -Rs` each [L4] entry; confirm `libayatana-appindicator` typelib name and `python3-six`. 2. Write `srcpkgs/python3-pynput/template`, `srcpkgs/python3-pywhispercpp/template` (Vulkan build option, `GGML_NATIVE=OFF`), `srcpkgs/vocalinux/template` + `INSTALL.msg`; `xlint` all three; `./xbps-src pkg` + runtime test. 3. Resolve PyAudio (update template locally to 0.2.14 first). 4. Add `tools/build-xbps.sh` (`podman`-friendly: runs inside `ghcr.io/void-linux/void-{glibc,musl}`), staging the canonical wheel. 5. Add the tag workflow (`voculinux-v*` or `v*` per §7): build matrix → sign with `XBPS_PRIVKEY` → publish release with full repodata → template-checksum bump commit. 6. README section: repo URL, fingerprint, `xbps-install -S` line, third-party-repo caveat [S6], CUDA/Vulkan note. 7. Smoke on real Void hardware: first-run model download, push-to-talk (evdev + `input` group), tray icon, Wayland + X11 injection. 8. (Optional, later) Upstream PR campaign per §7; `aarch64` builds. ## Sources Primary (Void / upstream): - [S1] void-packages *Manual.md* — template variables, Python packages, build options, `restricted`, triggers, `archs`: https://github.com/void-linux/void-packages/blob/master/Manual.md - [S2] `common/environment/build-style/python3-pep517.sh` + `common/build-style/python3-pep517.sh` (auto hostmakedepends, `python3 -m build --no-isolation --wheel`, `python3 -m installer`): https://raw.githubusercontent.com/void-linux/void-packages/master/common/build-style/python3-pep517.sh - [S3] void-packages *CONTRIBUTING.md* — package requirements, runtime testing, `xlint`, `xnew`, orphaned-package adoption: https://github.com/void-linux/void-packages/blob/master/CONTRIBUTING.md - [S5] Void Handbook, *Signing Repositories*: https://docs.voidlinux.org/xbps/repositories/signing.html - [S6] Void Handbook, *Custom Repositories*: https://docs.voidlinux.org/xbps/repositories/custom.html - [S7] `xbps-rindex(1)` man page (`--sign`, `--sign-pkg`, `--signedby`, `--privkey`): https://man.voidlinux.org/xbps-rindex.1 - [S8] `srcpkgs/python3/template` (3.14.8): https://raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/python3/template - [S9] `srcpkgs/nvidia/template` (nonfree, x86_64, `libcuda.so.1` only): https://raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/nvidia/template - [S13] `srcpkgs/libayatana-appindicator/template`, `srcpkgs/python3-gobject/template` (3.56.2, `py3:gi` provides): https://raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/python3-gobject/template - [S14] `srcpkgs/python3-evdev/template` (1.7.1, pep517), `srcpkgs/python3-PyAudio/template` (0.2.12_5, orphaned): https://raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/python3-PyAudio/template - [S15] `srcpkgs/python3-setuptools/template` (80.10.2): https://raw.githubusercontent.com/void-linux/void-packages/master/srcpkgs/python3-setuptools/template - [S16] PyPI JSON, `pynput` 1.8.2 `requires_dist`: https://pypi.org/pypi/pynput/json - [S17] PyPI JSON, `pywhispercpp` `requires_dist`: https://pypi.org/pypi/pywhispercpp/json Precedent (Bongbetic, first-party): - [S10] `Bongbetic/taema` `.github/workflows/release.yml` (tag `taema-v*` == `__version__`, void-glibc/musl containers, sign job, template bump): https://raw.githubusercontent.com/Bongbetic/taema/main/.github/workflows/release.yml - [S11] `Bongbetic/taema` `taema/tools/build-xbps.sh` (`xbps-create` without a void-packages checkout) and `taema/srcpkgs/taema/template`: https://raw.githubusercontent.com/Bongbetic/taema/main/taema/tools/build-xbps.sh - [S12] Personal memory `release-xbps.md` (tag-driven rule, key handling, `releases/latest/download` repository URL; 9-arch list is stale vs [S10]). Local checkout: - [L1] [pyproject.toml](/media/Toto/Documents/bongbetic/vocalinux/pyproject.toml:40) - [L2] [src/vocalinux/version.py](/media/Toto/Documents/bongbetic/vocalinux/src/vocalinux/version.py) - [L3] [packaging/aur/vocalinux/PKGBUILD](/media/Toto/Documents/bongbetic/vocalinux/packaging/aur/vocalinux/PKGBUILD) - [L4] [scripts/distro-package-map.yaml](/media/Toto/Documents/bongbetic/vocalinux/scripts/distro-package-map.yaml:177) - [L5] [install.sh](/media/Toto/Documents/bongbetic/vocalinux/install.sh:829) (CUDA toolkit validation ~L817–950, backend priority ~L1156–1175, `PYWHISPERCPP_VERSION` L287) - [L6] [docs/DISTRO_COMPATIBILITY.md](/media/Toto/Documents/bongbetic/vocalinux/docs/DISTRO_COMPATIBILITY.md:66), `install.d/system_dependencies.sh` (Void ~L484–503) - [L7] `packaging/` directory listing (no `void/`/`xbps/` subtree) - [L8] [packaging/native/nfpm.yaml](/media/Toto/Documents/bongbetic/vocalinux/packaging/native/nfpm.yaml:1) - [L9] [packaging/nix/pywhispercpp.nix](/media/Toto/Documents/bongbetic/vocalinux/packaging/nix/pywhispercpp.nix) - [L10] [.github/workflows/release.yml](/media/Toto/Documents/bongbetic/vocalinux/.github/workflows/release.yml:1) Method note: template presence (§4) was probed by HTTP status of each `srcpkgs/<pkg>/template` on void-packages `master`, 2026-11-05; a 404 means no template under that exact name (subpackages of another source package would not appear). Re-verify with `xbps-query -Rs` before implementation.
Sign in to join this conversation.