Package and publish

Test with pictures, pack a signed .zexec, push your source, and the store builds that exact commit. You never upload a binary.

Warning: this path is not proven end to end

The submission Worker, bot and publishing workflow are deployed, and the publish run produced an empty signed index. No real app has yet gone from submit through Accept to a listed build. The phone's store app cannot show these apps yet. Expect rough edges, and tell the moderators on Discord what you hit.

Test

zrn render out.png
zrn render --style metro out.png
zrn run --headless --script "wait 500; tap 180 170; type hi; wait 600; snap after.png; back; quit"
make check          # in the SDK: C, tool and Rust tests

Script steps are wait MS, tap X Y, drag X Y POINTS (a finger moving that far up over 200 ms), type TEXT, snap FILE, back and quit, separated by semicolons. A snapshot takes a while, so use one per run when timing matters.

In C tests, zui_layout, zui_inject_touch and zui_inject_text work with no display. Python has app.layout() and app.tap(), and Node.frame() says where something landed. ZUI_PERFLOG=1 prints what each frame costs the CPU.

Pack

$ zrn pack
zrn: made signing key A90978EBF45FDFE2 (~/.config/zrn/keys/dev.key); this user now trusts it
packed dist/io.github.you.notes-0.1.0-any.zexec (1120 bytes, sha256 ef4693336d58fd18...), signed by A90978EBF45FDFE2
$ zrn verify dist/io.github.you.notes-0.1.0-any.zexec
good: io.github.you.notes 0.1.0 (any), signed by A90978EBF45FDFE2
$ zrn install dist/io.github.you.notes-0.1.0-any.zexec
installed io.github.you.notes 0.1.0 -> ~/.local/share/zrn/apps/io.github.you.notes/io.github.you.notes.zexec
  app list: ~/.local/share/applications/io.github.you.notes.desktop

Output above is real, with paths shortened. A native package holds a program for one CPU, so one built on a laptop runs only on x86_64. Python packages are any. Until libzrnui ships in the system image, zrn pack --bundle-zrnui puts it inside the package.

What a .zexec is

#!/usr/bin/env zrn-exec\n      # chmod +x and run it
<zip archive>
  zexec.json                    # the manifest, first
  icon.svg | icon.png
  bin/<id>                      # native: the program
  lib/  share/                  # optional libraries and data
  app/                          # python3: the sources
<file>.zexec.minisig            # detached minisign-format signature

zrn-exec checks structure and signature before anything inside runs, unpacks once to ~/.cache/zrn/apps/<id>/<sha256>, and logs what the app prints to ~/.local/state/zrn/<id>.log. Packing is reproducible: the same commit gives the same bytes. Trusted keys live in /etc/zrn/trusted-keys, /usr/share/zrn/trusted-keys and ~/.config/zrn/trusted-keys. The format has not been cross-checked against the real minisign program.

Submit to the store

  1. Your app builds from a clean checkout. Rust crates are the only downloads allowed in a build.
  2. zrnapp.toml is complete, and the id is one you control.
  3. Push to a public GitHub repository. Other hosts are planned.
  4. zrn submit shows the entry for HEAD, which must be clean. zrn submit --send sends it.

Or on the ztOS Mobile Discord: /submit-app repo:https://github.com/you/notes commit:<40-digit SHA> [subdir:app].

What happens next

  1. The Worker checks the commit exists and reads zrnapp.toml at that commit.
  2. The bot opens a post in #ztos-app-submissions with the manifest, the permissions, and a link to the exact tree.
  3. A moderator reads the source and presses Accept or Reject, with a reason.
  4. Accept records the release in ledger/<id>.toml: the commit, who approved it and when.
  5. CI builds that commit with no secrets and no token, for aarch64 (Python once, for any CPU). A separate job signs it without running anything from the package, then publishes it to the signed index.

What gets you rejected

Updates

An update is a new submission: raise version, commit, push, zrn submit --send. Moderators see a compare link from your last approved commit. The store never follows a branch, so changing or force-pushing your repository does nothing to what is listed. If that removes the commit, the build fails rather than changes.

Revocation

A moderator can revoke a release for a security problem, abuse or a licence problem, with Revoke on the post or /revoke-app id version reason. The ledger records who, when and why, and the release leaves the index. The design says phones then disable it and show the reason, but the phone client for this does not exist yet. To recover, fix it and submit a new version.

Full rules: the store's CONTRIBUTING.md. Threat model: DESIGN.md.

Checked against zrn-sdk commit ea16771. Pictures are real renders of code that compiled. Source and proof.