Development and packaging
Prerequisites
Section titled “Prerequisites”ClamUI supports Python 3.11+, GTK 4.6+, and libadwaita 1.1+. Source PyGObject>=3.56.3 needs GLib 2.80+, so stock Ubuntu/Pop!_OS 22.04 (GLib 2.72) cannot satisfy the current source dependency floor even though the UI remains compatible with their GTK/libadwaita floor. Use Flatpak or a newer development host there.
Debian or Ubuntu
Section titled “Debian or Ubuntu”sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-4.0 gir1.2-adw-1 libadwaita-1-dev libgirepository-2.0-dev libcairo2-dev pkg-config python3-dev libjpeg-dev zlib1g-dev clamav gir1.2-dbusmenu-0.4Fedora
Section titled “Fedora”sudo dnf install python3-gobject python3-gobject-devel gtk4 libadwaita gobject-introspection-devel cairo-gobject-devel clamav libdbusmenuArch Linux
Section titled “Arch Linux”sudo pacman -S python-gobject gtk4 libadwaita clamav libdbusmenu-glibUse libgirepository1.0-dev rather than libgirepository-2.0-dev on Ubuntu releases before 24.04.
Install uv before creating the environment:
curl -LsSf https://astral.sh/uv/install.sh | shOpen a new shell if the installer changes your PATH.
Work on the app
Section titled “Work on the app”git clone https://github.com/linx-systems/clamui.gitcd clamuiuv sync --locked --extra devuv run clamuiuv run clamui /path/to/file-or-folderuv run clamui scan /path/to/fileuv run clamui quarantine listuv run clamui profile listuv run clamui statusuv run clamui historyuv run clamui helpuv run clamui-scheduled-scan --helpUse relative imports inside src/; absolute src.* imports break installed packages. User-facing strings need gettext marking, and GTK/UI work must return to the main loop through GLib.idle_add(). Read the repository’s AI and contributor guide for detailed conventions.
The native-host-only sudo clamui install-privileged-helper installs the root-owned preference helper and polkit policy. Do not run it inside Flatpak; install the matching helper package on the host instead.
Save and scan workflow ownership
Section titled “Save and scan workflow ownership”src/core/preferences_save.py owns Save & Apply proposal validation and
persistence. The preferences window supplies current configuration state;
SavePage collects widget values and prepares a detached proposal on the GTK
thread. The worker applies that proposal without reading live widgets or window
state. Its result identifies which configs are durable, even if later settings
or scheduler work fails. The GTK completion commits each config only if its
selected path still matches the click-time state, then presents the outcome.
Keep privileged writes in the existing ClamAV config writer; the workflow is not
an atomic transaction across all destinations.
src/core/scan_result_interpreter.py interprets both clamscan and
clamdscan output. Shared detection and result rules live here, not in scan
execution. The two entry points retain distinct evidence: standalone summary
counts and progress fallback, versus daemon pre-counts and genuine error replies.
Keep subprocess lifecycle, cancellation, and host execution in the scanner
modules.
Exercise these value-level interfaces with
tests/core/test_preferences_save.py and
tests/core/test_scan_result_interpreter.py; retain scanner execution and GTK
completion coverage for their integration.
Maintain local Repowise architecture guidance
Section titled “Maintain local Repowise architecture guidance”Repowise indexes and configuration live in the ignored .repowise/ directory. They are local machine state, so do not commit them or put provider credentials in them. After creating or recovering a local index, restore this guidance block in the root .repowise/config.yaml before generating architecture prose:
generation_context: token_budget: 8000 files: repo_overview: - src/ui/scan/AGENTS.md - src/app.py onboarding/getting_started: - src/ui/scan/AGENTS.md - src/app.py onboarding/key_concepts: - src/ui/scan/AGENTS.md - src/app.py onboarding/how_it_works: - src/ui/scan/AGENTS.md - src/app.py onboarding/active_landscape: - src/ui/scan/AGENTS.md - src/app.pyThe indexed guidance records the current boundary: src/ui/scan_view.py:ScanView,
created by ClamUIApp.scan_view in src/app.py, is the active desktop scan
screen. src/ui/scan/ is a modular alternative; its ScanCoordinator and
ScanController are not constructed by the current application route.
For an approved repair with the Claude CLI provider, first inspect the local generation plan:
repowise generate --page repo_overview:clamui --cascade none --provider claude_cli --model claude-haiku-4-5 --dry-runclaude_cli uses the Claude subscription rather than a local Ollama model.
Only after the plan has been reviewed and the subscription use has explicit
approval, write the page:
repowise generate --page repo_overview:clamui --cascade none --provider claude_cli --model claude-haiku-4-5 --yesRepowise records the selected guidance in the generated page metadata under
source_evidence; for the overview, confirm that it lists both
src/ui/scan/AGENTS.md and src/app.py as included. This grounding makes the
fact available on later regeneration, but generated prose still requires
review: an LLM cannot be guaranteed to reproduce every fact perfectly.
To pin a correction while prose is being regenerated, use the dashboard API’s
PATCH /api/pages/lookup/notes?page_id=<page-id> endpoint with
human_notes. The note survives model regeneration and is returned by the
dashboard page APIs. It is not a retrieval guarantee: MCP get_context
includes it only for file pages, while get_overview and search do not expose
it. Keep the source guidance above as the durable correction.
Restore local Repowise semantic search
Section titled “Restore local Repowise semantic search”Both the root repository and website/ have separate ignored Repowise state.
In each local .repowise/config.yaml, set:
embedder: ollamaembedding_model: embeddinggemmaIn each corresponding ignored .repowise/.env, set the local embedding
connection values:
OLLAMA_BASE_URL=http://127.0.0.1:11434OLLAMA_EMBEDDING_MODEL=embeddinggemmaOLLAMA_EMBEDDING_DIMS=768With Ollama and embeddinggemma available locally, rebuild both vector stores
from the repository root:
repowise reindex . --embedder ollamarepowise reindex website --embedder ollamaReindexing embeds existing pages locally and does not generate prose. Restart the Repowise MCP server and dashboard after reindexing so they reconnect to the updated local semantic indexes.
Validate before a pull request
Section titled “Validate before a pull request”uv run ruff check .uv run ruff format --check .pytestpytest --cov=src --cov-report=term-missing./scripts/hooks/install-hooks.shTests mirror source beneath tests/; tests/conftest.py provides GTK fixtures. The project targets 50% total coverage, 80%+ for core/profiles, and 70%+ for UI. CI tests Python 3.11–3.14 and retains an Ubuntu 22.04/libadwaita 1.1 compatibility job.
Packaging boundaries
Section titled “Packaging boundaries”Flatpak builds against GNOME 51, whose native Python runtime is 3.14; generated Flatpak wheel sources target 314-x86_64 and 314-aarch64. This bundled runtime is independent of the host GTK/Python stack. Flatpak and AppImage carry Python and GUI dependencies but never ClamAV: all formats use host clamscan, freshclam, and optionally clamd/clamdscan. The full Debian application package requires host Python 3.11+ (stock Debian 12+ or Ubuntu 24.04+); use Flatpak on Ubuntu/Pop!_OS 22.04. Flatpak host calls and configuration at the selected distribution-specific paths remain explicit boundaries. The Debian application and matching privileged-helper packages must be version-matched.
Build paths and package metadata live in flathub/, appimage/, and debian/. Use their checked-in scripts and manifests rather than duplicating package logic.
Install flatpak-builder from your distribution. On Debian or Ubuntu:
sudo apt install flatpak-builderAfter setting up Flathub, install the matching SDK and runtime:
flatpak install flathub org.gnome.Sdk//51 org.gnome.Platform//51Build package artifacts from the repository root:
flatpak-builder --user --install --force-clean build-dir flathub/io.github.linx_systems.ClamUI.local.yml./appimage/build-appimage.sh./debian/build-deb.shThe Flatpak local manifest intentionally sources the working tree; its production manifest sources the pinned release. AppImage builds need Ubuntu 24.04+ GTK/libadwaita packages, Python, wget, and FUSE to run the artifact. Debian builds require dpkg-deb and fakeroot and produce both version-matched .deb files.
Update the application icon
Section titled “Update the application icon”icons/io.github.linx_systems.ClamUI.svg is the source icon; icons/io.github.linx_systems.ClamUI.png is its checked-in 128×128 rendering. When the SVG changes, regenerate and commit both files once. Builds install the committed PNG and never convert it.
rsvg-convert --width=128 --height=128 --output=icons/io.github.linx_systems.ClamUI.png icons/io.github.linx_systems.ClamUI.svgOn Debian or Ubuntu, install the converter separately:
sudo apt install librsvg2-binWrite documentation
Section titled “Write documentation”The website’s Starlight documentation source is website/src/content/docs/docs/; add a focused Markdown/MDX page there, use root-relative /docs/.../ links, and update the Starlight sidebar in website/astro.config.mjs. Keep root README.md, CONTRIBUTING.md, SECURITY.md, and CODE_OF_CONDUCT.md as short GitHub discoverability pointers, not parallel manuals. CHANGELOG.md and RELEASE_NOTES.md remain release inputs and are rendered by MDX imports rather than copied.
The project chose Starlight inside the existing Astro site at /docs/ for stock navigation, search, and code-copy UI without a separate CMS, server, or search service. Website commands:
cd websitebun install --frozen-lockfilebunx playwright install --with-deps chromiumbun run devbun run checkbun run buildKeep pagefind and @pagefind/default-ui pinned to 1.4.0. Pagefind 1.5 workers use root-relative URLs that fail in WorkerGlobalScope on static hosts. Lift the pin only after browser search passes both a direct docs load and the marketing-to-docs navigation path.
Do not edit generated website/public/ asset copies; the website scripts synchronize root icons and screenshots. Keep release documentation sourced from the root files.