A software directory and one-click installer for Kali Linux — the "app store" experience Windows users expect, built on top of apt and GitHub releases.
- A real directory with real folders. Every app gets a link record filed in a
category folder on disk (
~/.local/share/cm-appcenter/library/), so the catalogue is browsable with any file manager, greppable, and diffable. - Links, not files. A record stores the direct download URL for the latest release, its version, size and asset name. Nothing is downloaded until you run the install wizard.
- Keeps itself current. A systemd user timer re-resolves every link daily and scans GitHub weekly for newly released open-source apps.
- Auto-categorisation. A newly discovered movie player is filed into
Movies & Video; a password cracker lands inSecurity & Pentest. If a category folder does not exist yet, it is created. - Install like on Windows. Pick an app, click Install, approve the password prompt if one is needed, done. It shows up in your application menu.
git clone https://github.com/consistentmessage-web/cm-appcenter.git \
~/.local/share/cm-appcenter
~/.local/share/cm-appcenter/install.shThen launch CM App Center from your application menu, or run cm-appcenter.
Requirements: Python 3.11+, PyQt6 (sudo apt install python3-pyqt6), and a
Debian-based system with apt and pkexec.
| Method | What happens | Password? |
|---|---|---|
apt |
apt-get install from the Kali/Debian repository |
yes |
deb |
downloads the .deb from the GitHub release, installs with apt |
yes |
appimage |
downloads the AppImage, extracts its icon, adds a menu entry | no |
tarball |
downloads and extracts the release archive, links binaries onto PATH |
no |
binary |
downloads the released binary onto PATH |
no |
pipx |
installs into an isolated Python environment | no |
git |
no releases at all: installs from source (see below) | no |
script |
runs the project's official installer script (shown before it runs) | usually |
Plenty of well-known tools ship no packaged binaries — usbkill has 4.6k stars,
zero releases and zero topics. Those are installed from source, with the build
strategy detected from the repository's root files:
| Detected | Strategy |
|---|---|
pyproject.toml / setup.py |
pipx install git+https://… into its own venv |
requirements.txt + a script |
clone, build a venv, write a wrapper onto PATH |
| an executable script at the root | clone, chmod +x, link onto PATH |
go.mod |
go install …@latest into ~/.local/bin |
| none of the above | not installable — the App Center says so and links the project |
Removal is tracked per app: the App Center records exactly what it installed
(package name, binaries, .desktop file, icon) and reverses precisely that.
cm-appcenter # the GUI
cm-appcenter --refresh # re-resolve every direct link
cm-appcenter --discover # scan GitHub for new apps and file them
cm-appcenter --find usbkill # live GitHub lookup, adds what it finds
cm-appcenter --prune # drop duplicates and non-applications
cm-appcenter --list "Movies & Video"
cm-appcenter --search wireshark
cm-appcenter --install obsidian
cm-appcenter --remove obsidian
cm-appcenter --sync # rebuild the folder tree from the catalog
cm-appcenter --self-update # git pull the App Center itselfThe catalogue is seeded with curated apps and grown by scanning GitHub, so something can be missing for three reasons — all of which the App Center now handles:
- No topics. Discovery searches GitHub topics and name/description wording, because topics are optional and many projects set none.
- No releases. A repo with no downloadable asset used to be discarded; it is now kept and installed from source when the build shape is recognisable.
- Not in your local catalogue yet. Type a name into the search box and the
App Center offers to look it up on GitHub live (
--findon the command line), adding it to the right category folder on the spot.
If a project genuinely cannot be installed — an Android-only APK such as AirGuard, or a repo of wordlists — it says which of those it is and links you to the project instead of silently showing nothing.
Picking the right file out of a GitHub release is most of the work. Every asset
is scored: wrong architectures and operating systems are rejected outright
(arm64, i686, .rpm, darwin, windows…), sub-packages are demoted
(-help, -server, -dev, sciter), package formats are ranked
(.deb > .AppImage > tarball > raw binary), and a per-app asset_regex in the
seed catalogue pins the exact file when a project ships something unusual.
This is why RustDesk resolves to rustdesk-x86_64.deb rather than the armv7
sciter build, and ONLYOFFICE to the editor rather than its help pack.
Unauthenticated GitHub allows 60 requests/hour, which is not enough for a full
scan. The App Center uses, in order: $GITHUB_TOKEN, ~/.local/state/cm-appcenter/github.token,
or gh auth token if the GitHub CLI is logged in — any of which raises the limit
to 5000/hour. Responses are cached on disk with ETag revalidation, so repeat
refreshes are nearly free.
~/.local/share/cm-appcenter/ code, seed catalogue, installer
cm_appcenter/ the Python package
data/catalog.seed.json curated apps
data/cm-appcenter.svg icon source; data/bake_icon.py bakes the PNGs
library/<Category>/<app>.json link records (auto-generated)
~/.local/state/cm-appcenter/ merged catalog, installed.json, log
~/.cache/cm-appcenter/ GitHub API cache, transient downloads
~/.local/opt/cm-appcenter/<app>/ AppImages and extracted archives
Add an entry to data/catalog.seed.json and run cm-appcenter --refresh:
{
"id": "obsidian",
"name": "Obsidian",
"summary": "Markdown knowledge base that works on local folders",
"category": "Office & Productivity",
"method": "deb",
"repo": "obsidianmd/obsidian-releases",
"asset_regex": "^obsidian_.*_amd64\\.deb$"
}MIT.

