Build system & developer toolkit for M5CardputerZero
applications. Submit any public Git repository and get a ready-to-install
.deb package — no local toolchain required — then publish it to the
CardputerZero AppStore with the Python czdev CLI.
czdev— a small, pure-Python 3 CLI to scaffold a new app, authenticate with GitHub and publish / unpublish.debpackages. No Rust / cargo toolchain needed.- CI online build — a GitHub Actions workflow that cross-compiles any repo
to an aarch64
.deb. - Examples — a gallery of ready-to-build apps (C/LVGL, SDL2, Qt, Python,
Rust) under
examples/.
git clone https://github.com/CardputerZero/CardputerZero-AppBuilder.git
cd CardputerZero-AppBuilder
./czdev --help # works immediately with Python 3
./czdev login # one-time GitHub device-flow login
./czdev new my-app # scaffold a project from the latest template
# From your app's project directory (must contain app-builder.json with a
# "store" section), after producing a .deb:
./czdev bump --deb build/my_app_1.0.0_arm64.deb # show next version
./czdev publish --deb build/my_app_1.0.1_arm64.deb # open a publish PRRequirements: Python 3, git, dpkg-deb.
czdev is the repo-root wrapper (./czdev) around the Python package in
scripts/czdev/. You can also run it as a module:
PYTHONPATH=scripts python3 -m czdev --help| Command | What it does |
|---|---|
czdev new NAME |
Scaffold a new app from the project template. See Starting a new app. |
czdev login |
GitHub OAuth device flow; stores a token at ~/.czdev/credentials. |
czdev logout |
Remove the stored GitHub credentials. |
czdev bump [--deb PATH] |
Print the next patch version for a package (reads the version from the .deb). Defaults to ./build/*.deb. |
czdev publish [--deb PATH] |
Validate the .deb and open a publish PR against the packages repo. Defaults to ./build/*.deb. |
czdev unpublish NAME --version V [--arch arm64] |
Open a PR that removes a published package version. |
Package names are first-come, first-served by GitHub login: whoever first publishes a package name owns it. Afterwards only that uploader (or a repo admin) can publish new versions or unpublish it. The uploader's login is recorded in the release manifest and enforced server-side — there is no email-address matching.
┌──────────────────────────────────────────────────────────────────────────────┐
│ czdev publish — End-to-End Flow │
└──────────────────────────────────────────────────────────────────────────────┘
┌─────────┐ ┌─────────┐ ┌──────────┐ ┌─────────────┐
│ LOGIN │────────▶│ BUILD │────────▶│ PUBLISH │────────▶│ REVIEW │
└─────────┘ └─────────┘ └──────────┘ └─────────────┘
│ │ │ │
▼ ▼ ▼ ▼
czdev login CI workflow czdev publish Admin merges
(GitHub OAuth ─▶ .deb artifact --deb xxx.deb the PR
Device Flow) ┌────────────┐ │
│ │ Preflight: │ ▼
▼ │ • .desktop │ ┌───────────┐
Token saved │ • version ✓│ │ RELEASE │
~/.czdev/ │ • size ✓ │ └───────────┘
credentials │ • no root │ │
│ └─────┬──────┘ ▼
▼ │ APT repo updated
Verified emails ▼ App live in Store
(user:email) Upload .deb to
GitHub Release
─▶ metadata PR
on packages
Timeline:
You (Developer) czdev GitHub (Remote)
─────────────── ───── ───────────────
│ │ │
│── czdev login ─────────────▶│── OAuth Device Flow ──────▶│
│ │◀── access token ───────────│
│ │ │
│── czdev publish ───────────▶│ │
│ │── validate .deb ───────────│ (version/size/root)
│ │── upload .deb to Release ──▶│
│ │── commit metadata + PR ───▶│
│◀── PR URL ──────────────────│ │
│ │ │
│ │ Admin reviews & merges
│ │ CI rebuilds the APT index
│ │ │
│◀───────────────────── App available in AppStore ─────────│
│ │
The .deb binary is uploaded to a GitHub Release; only small metadata
(meta.json, screenshots, icon, release manifest) is committed in the publish
PR. See docs/APP_BUILDER_JSON.md for the
store section that supplies the AppStore listing (title, summary,
screenshots, categories, …).
New projects start from CardputerZero/Template (LVGL + CMake, desktop SDL preview + device framebuffer build). Two equivalent ways to get a copy — both always give you the template's latest state:
# A. via czdev (clones the template's default branch, renames placeholders)
./czdev new my-app
# B. via GitHub's template mechanism (creates a fresh repo under your account)
gh repo create my-app --template CardputerZero/Template --public --cloneczdev new additionally does the per-app renaming that the template needs:
the CMake project name, the compiled-in APP_NAME, the launcher display name,
and — importantly — the icon files. The template's icons install into the
shared /usr/share/APPLaunch/share/images/, so leaving them named
template*.png makes two template-derived packages conflict on install.
./czdev new my-app --display-name "My App" # launcher name (default: "My App" from the slug)
./czdev new my-app --dir ~/projects/my-app # target directory (default: ./my-app)
./czdev new my-app --template me/MyTemplate # a different template repo, or a git URL
./czdev new my-app --ref dev # a different template branch
./czdev new my-app --no-git # don't create a git repoNAME must be a valid Debian package name (lowercase, starts with a letter),
because it becomes the package name at publish time.
Why not a git submodule? A submodule stores a gitlink — an exact commit SHA — in the parent tree, so AppBuilder would freeze every developer on whichever template commit happened to be vendored, and each template update would need a commit here.
czdev newcopies the branch tip at scaffold time instead, so there is no pinned commit anywhere. The trade-off is that a scaffolded project is not linked to upstream: later template changes must be cherry-picked manually (which is the normal expectation for a scaffold — same ascargo new).
You don't need a local ARM toolchain — building happens in CI.
-
Go to Actions → Build DEB Package → Run workflow.
-
Fill in the form:
Field Required Example Description Repository URL Yes https://github.com/CardputerZero/M5CardputerZero-Launcher.gitAny public HTTP Git URL (GitHub, GitCode, Gitee, …) Branch No masterLeave empty to use the repository's default branch -
The workflow scans for
app-builder.jsonfiles, builds each project, and packages them as.deb. -
Download the
.debfrom the run's Artifacts section.
Pushing to this repo runs Build APPLaunch .deb packages
(.github/workflows/build-debs.yml), which builds every app under
examples/ and attaches the .debs as artifacts. Prebuilt
examples are also kept under dist/.
scp <package>_arm64.deb pi@<device-ip>:/tmp/
ssh pi@<device-ip> "sudo dpkg -i /tmp/<package>_arm64.deb"The CI pipeline runs on x86_64 and cross-compiles to ARM64 (aarch64) using
the aarch64-linux-gnu- toolchain — the same approach used by the
M5Stack_Linux_Libs SDK.
User Input (repo URL)
│
▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ git clone │────▶│ discover │────▶│ build │────▶│ dpkg-deb │
│ --recursive │ │ app-builder │ │ (x86→arm64) │ │ packaging │
└──────────────┘ │ .json │ └──────────────┘ └──────────────┘
└──────────────┘ │
│ ▼
N projects N × .deb artifacts
(parallel) (download)
Generated packages follow the APPLaunch packaging conventions:
<package>.deb
├── DEBIAN/
│ ├── control
│ ├── postinst (enable & start systemd service)
│ └── prerm (stop & disable service)
├── lib/systemd/system/
│ └── <package>.service (runs as a non-root user; root services are rejected)
└── usr/share/APPLaunch/
├── applications/<package>.desktop
├── bin/<executable>
├── lib/
└── share/
├── font/*.ttf
└── images/*.png
czdev: python3 not found— install Python 3 and re-run.app-builder.json not found— runczdev publishfrom your app's project directory; the file must contain astoresection with at least one 320×170 screenshot.not the owner of <package>— that package name is already owned by another GitHub account (first-come, first-served). Pick a different name or ask the owner / a repo admin.- Publish rejected: service runs as root — apps must not run as root. Pin
the bundled systemd service to a non-root user (
User=<non-root>in the[Service]section) and rebuild the.deb.
- M5CardputerZero-UserDemo — Reference user demo application
- M5Stack_Linux_Libs — SDK with SCons build system
- m5stack-linux-dtoverlays — Device tree overlays & drivers
MIT