neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
翻譯準備中
Android terminal that runs Alpine / Ubuntu / Arch / Kali without root — plus a Linux GUI, SSH/SFTP, a Japanese IME, and shell access to Android itself (notifications, sensors, event-driven automation).
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
A terminal for Android that is also a way to drive Android.
Z2Term runs Alpine / Ubuntu / Arch / Kali without root, opens a Linux desktop in a tab,
and lets the shell reach the phone itself — read a notification, ask you a question in the
notification shade, or run a script when the battery, the network or an incoming SMS changes.檢視完整 README ↗English ・ 日本語
Z2Term runs Alpine / Ubuntu / Arch / Kali without root, opens a Linux desktop in a tab, and lets the shell reach the phone itself — read a notification, ask you a question in the notification shade, or run a script when the battery, the network or an incoming SMS changes.
apk / apt / pacman. The default execution engine (z2root) is a ptrace-based userspace implementation written for this app.z2-* helpers (notifications, clipboard, sensors, torch, intents, alarms, wireless adb to the device itself) plus z2-when — an automation hub that runs scripts on device events and keeps working after a reboot without the app being opened.z2-edge builds edge panels that float over other apps: commands, macros and app launches as buttons, plus notes and a mini terminal. The handle at the screen edge takes a sequence of actions for each of six gestures. Both can be edited on screen. See the handbook.z2-action sends taps, swipes and gestures. Steps live in a plain text file with repeats and conditions, and can also be edited on screen or recorded by tracing with a finger. See the format and examples.z2-ui reads the foreground app's screen as JSON, taps elements by number and enters text, even in apps without an API. It is off by default; each app can be set to read only, ask each time and so on, and a notification lets you pause, instruct or stop the AI while it works. It also speaks MCP: register ssh <phone> z2-ui mcp in your PC's AI to use it as tools. How it works.The 5th project of the Zero to Ship initiative.
Android already has a mature terminal ecosystem, and Termux is the right answer if what you want is the largest package repository and the most battle-tested tooling. Z2Term is built around a different question: what if the terminal were a first-class way to operate the phone, and everything came in one APK?
| Z2Term | Termux + its add-ons | |
|---|---|---|
| Full Linux distribution | Alpine / Ubuntu / Arch / Kali on z2root | proot-distro package installs one |
| Linux GUI | Built-in GUI tab (Xvnc + an RFB client inside the app), with audio and video. The same viewer also opens a remote VNC or RDP desktop | A separate X11, VNC or RDP viewer app |
| Drive Android from the shell | Built in — ~40 z2-* helpers | A separate companion app |
| Event-driven automation | Built in — z2-when (charging, battery level, time / cron, Wi-Fi, connectivity, boot, share, SMS, sensors, notifications, new files) with an Automation tab, logs and a kill switch | A separate companion app, usually paired with a third-party automation app |
| Japanese input | Built-in IME (conversion, prediction, learning), also selectable as the OS input method | The OS keyboard |
SSH / SFTP, FTP, WebDAV and SMB clients, plus sshd | Built in; services use SSH port forwarding by default, SSH keys held by the Android Keystore | Install the packages yourself |
| Distribution | GitHub Releases (this repo) | F-Droid and its own repository |
Both are GPL-3.0 and neither collects telemetry. If you already have a Termux setup you are happy with, Z2Term's reason to exist is the second, third and fourth rows of that table.
Double-tap ⌨ in the toolbar to show or hide the keyboard. Settings → Key layout (your own) includes the OS-keyboard accessory bar toggle and an editor for its keys, shared by terminal and GUI tabs. Local GUI menus can use the Android device’s existing Japanese fonts; reopen GUI after updating.
You can download the latest APK directly from GitHub Releases (no build needed):
Every release ships one APK: z2term-<version>.apk. See the release page for its size.
It bundles no OS and no third-party prebuilts, so the first launch asks you to pick a distribution in Settings › Linux environment (Alpine is fetched from the official CDN, verified by SHA-256, and updates never re-download it). Automatic updates (below) fetch the whole APK each time.
⚠ Up to 0.8.358 there was a second, ~190MB APK with Alpine bundled (the full flavor).
0.8.359 dropped it — it only saved that one first download, while making everyone choose between
two files. If you are on a full install, this APK updates it in place (same package ID).
Tap the APK on your Android device → allow "Install from unknown sources" to install. (Not distributed on Google Play.)
Pick whichever fits:
z2-update (--check / --keep / --dir). The downloaded APK is deleted after the update by
default. ⚠ Installed from F-Droid or a store? Then it refuses and points you back there.https://github.com/orgsonai/z2term to
Obtainium. It watches these Releases and updates the app
with one tap when a new version appears — no app store involved. The Linux OS is not downloaded again.Changes in each version are listed in docs/en/CHANGELOG.md.
z2-edge defines an edge bar or draggable button and panels with command buttons, text, toggles, lists and input fields. Shell commands supply the contents; push and badge update them from automation. z2-key exposes Android global actions through an optional accessibility service, and z2-app lists launchable apps and exports their icons. See the handbook. Overlay permission is opt-in; no external helper app is required.apk / apt / pacman.z2-usb list, then z2-usb allow [number] and approve Android's device permission; programs using libusb or /dev/bus/usb/... can then open it without being patched. A normal data-capable USB-A-to-USB-C adapter or hub works when the phone supports USB Host/OTG.z2gui starts a desktop and z2run <app> launches a GUI app (opening the GUI tab for you), with audio and video. The same viewer also connects to a remote VNC or RDP desktop: a saved host gets [VNC] and [RDP] buttons that open that machine's desktop in a tab (VNC: RFB 3.3-3.8, None / VNC-password auth; RDP: Network Level Authentication with a first-use certificate check, mouse and keyboard input, text clipboard sharing, and as ).| Item | Version |
|---|---|
| Android Studio | Ladybug 2024.3.1 or later |
| AGP | 9.1.1 |
| Kotlin | 2.2.10 (bundled with AGP) |
| Gradle | 9.3.1 |
| NDK | 27.0+ |
| CMake | 3.22.1+ |
| Other tools | Python 3, curl, tar, sha256sum |
| Min SDK | 29 (Android 10) |
| Target SDK | 35 (Android 15) |
Several artifacts are bundled into the APK but kept out of git (built/fetched by scripts/), so a fresh clone or a clean has none of them. Collect them with the master script on a PC:
bash scripts/build-bundle.sh
It runs two generators and verifies the common payload:
build-z2root.sh → libz2root.so / libz2accept.so (needs an NDK)fetch-fonts.sh → IBMPlexMono / JetBrainsMono / FiraCode -Regular.ttf (tracked in git from 1.0.4, so this normally does nothing)A final manifest step prints OK / MISS per artifact. Linux rootfs archives are downloaded at runtime and are never APK build inputs.
Per-artifact details: app/src/main/assets/README.md · app/src/main/jniLibs/README.md
./gradlew assembleRelease
# Output: app/build/outputs/apk/release/app-release.apk
(No signing key required for forks — build.gradle.kts falls back to the debug key when keystore.properties is absent.)
adb install -r app/build/outputs/apk/release/app-release.apk
z2term/
├── app/
│ ├── build.gradle.kts
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── assets/ ← place the Alpine rootfs here
│ ├── cpp/ ← JNI native code
│ │ ├── CMakeLists.txt
│ │ └── pty_jni.cpp
│ ├── java/com/zerotoship/z2term/
│ │ ├── Z2TermApplication.kt
│ │ ├── MainActivity.kt
│ │ ├── channel/ ← ProcessChannel / SshChannel (M5)
│ │ ├── core/ ← TerminalSession + SessionManager
│ │ ├── pty/ ← PTY abstraction
│ │ ├── proot/ ← Linux launch (legacy package name)
│ │ ├── distro/ ← rootfs deployment (Alpine + Ubuntu)
│ │ ├── emulator/ ← VT100/xterm emulator core
│ │ ├── settings/ ← DataStore persistence
│ │ ├── service/ ← TerminalService / AudioBridge (foreground + WakeLock)
│ │ ├── gui/ ← GUI (Xvnc + built-in RFB client / GuiSession)
│ │ ├── saf/ ← SAF DocumentsProvider
│ │ └── ui/
│ │ ├── theme/ ← ZTS Theme + custom fonts
│ │ ├── settings/ ← settings UI
│ │ ├── ssh/ ← SSH profile UI (M5)
│ │ └── terminal/ ← terminal UI + Renderer + key mapper
│ ├── jniLibs/ ← generated z2root binaries
│ └── res/ ← resources
├── build.gradle.kts
├── settings.gradle.kts
├── gradle/
│ ├── libs.versions.toml
│ └── wrapper/
├── docs/
│ ├── ja/ ← Japanese documentation
│ │ ├── DESIGN-SPEC.md ← design & specification (technical)
│ │ ├── HANDBOOK.md ← user handbook
│ │ └── MACRO-GUIDE.md ← phone-automation macro guide (AI-friendly)
│ ├── en/ ← English documentation
│ │ ├── DESIGN-SPEC.md ← design & specification
│ │ ├── HANDBOOK.md ← getting started handbook
│ │ └── MACRO-GUIDE.md ← phone-automation macro guide (AI-friendly)
│ ├── images/ ← screenshots etc. (shared)
│ ├── RELEASE.md ← release steps
│ ├── FDROID.md ← F-Droid submission steps
│ └── SSH-INTO-Z2TERM.md
├── metadata/ ← F-Droid metadata (store listing)
└── .github/workflows/build.yml ← CI (build, lint, tests, signed release APK)
Only build types differ. The distribution flavors (full / foss) were dropped in 0.8.359 —
one build for everyone, with the rootfs always fetched at runtime.
| Build type | applicationId | Launcher name |
|---|---|---|
release | com.zerotoship.z2term | Z2Term |
debug | com.zerotoship.z2term.debug2 | Z2Term dbg2 |
The suffix lets a debug build sit next to a release one, and the name tells them apart.
./gradlew assembleDebug
z2version reports engine : z2root, then test the distro package manager.scripts/z2root-cmdtest.sh)A regression smoke test for confirming that fragile commands keep working
going forward on the z2root engine — focused on the hard paths (ptrace/seccomp,
fakeroot fakery, path translation, /proc fakery, pty, heavy fork/exec, ld.so
reloc), not trivial cd/ls. The point is to catch a systemic z2root regression
as "many commands fail at once" instead of discovering each broken command later.
Run it inside a started guest (any distro) on the z2root tab:
sh scripts/z2root-cmdtest.sh # standard (incl. network/build)
SKIP_NET=1 sh scripts/z2root-cmdtest.sh # skip network/package steps
SKIP_BUILD=1 sh scripts/z2root-cmdtest.sh # skip cc compile etc.
RUN_SSHD=1 sh scripts/z2root-cmdtest.sh # dropbear loopback ssh (may reset the session under z2root!)
RUN_PRIV=1 sh scripts/z2root-cmdtest.sh # also run truly-root ops (losetup/mount); EPERM is normal on non-root z2root
It is POSIX sh / busybox-ash compatible and skips missing commands rather than
failing, so it runs identically across distros — run it on each guest and a
healthy engine yields an empty "non-zero exit" summary everywhere. 10 groups:
① runtime real-launch (claude headless vs --version, node spawn, python
venv/multiprocessing/ssl, ripgrep), ② heavy VCS (git clone/gc/checkout =
hardlink/pack/rename), ③ package managers (apt/apk/dnf/pacman, pip/venv, npm =
fakeroot/fork-exec/symlink), ④ pty/terminal (script/tmux/stty, /dev/pts,
optional dropbear loopback), ⑤ /proc/fakeroot boundary, ⑥ build (cc execve
chain + ld.so reloc), ⑦ path translation / symlink canonicalization, ⑧ disk/FS
(dd, mkfs, parted on file images; root ops behind RUN_PRIV), ⑨ IPC / special
syscalls (AF_UNIX, FIFO, flock, inotify, xattr, copy_file_range, nested ptrace
via strace/gdb, Go raw syscalls, sqlite3, rsync), ⑩ name resolution / TLS
(getent, curl TLS, nslookup). Output goes to the screen and
/tmp/z2root-cmdtest-<timestamp>.log; a trailing summary lists any non-zero
exits.
Note: io_uring (bypasses ptrace/seccomp entirely) and statx/openat2 hook
gaps can't be caught by command tests — verify those at the seccomp-filter level.
Everything written for this project — the app (app/src/main/java/**), the native code including the execution engine (app/src/main/cpp/**), and the scripts and docs in this repository — is licensed under GPL-3.0-only.
Copyright (c) 2026 Zero to Ship. Corresponding source (GPL v3 §6): https://github.com/orgsonai/z2term (full text in the root LICENSE).
Bundled third-party notices are available from Settings → OSS licenses.
| Bundled item | License | How to get the corresponding source |
|---|---|---|
| ZXing Core 3.5.3 | Apache-2.0 | zxing/zxing 3.5.3 |
| ZXing Android Embedded 4.3.0 | Apache-2.0 | journeyapps/zxing-android-embedded v4.3.0 |
| AndroidX / Jetpack Compose | Apache-2.0 | Android Open Source Project |
| Kotlin Standard Library / Coroutines 1.7.3 | Apache-2.0 | JetBrains/kotlin / kotlinx.coroutines 1.7.3 |
| JSch / JZlib / jBCrypt | BSD-3-Clause / ISC | mwiede/jsch / ymnk/jzlib / jBCrypt |
| OkHttp 5.3.0 | Apache-2.0 | square/okhttp |
| Okio 3.16.2 | Apache-2.0 | square/okio 3.16.2 |
| SMBJ 0.15.0 | Apache-2.0 | hierynomus/smbj v0.15.0 |
| asn-one 0.6.0 | Apache-2.0 | hierynomus/asn-one v0.6.0 |
From the settings screen → "OSS licenses / corresponding source", you can also browse/show this in-app
(license full texts are placed in assets/licenses/).
| Channel | Status |
|---|---|
| GitHub Releases / direct APK | Primary channel; one APK per release |
| F-Droid | Prepared for submission, not published yet. Runtime-downloaded rootfs; fully source-built engine (docs/FDROID.md) |
| Google Play | No distribution planned |
The in-terminal sshd command starts by default with 127.0.0.1-only bind + key auth only
(dropbear wrapper, SshdScript.kt). To expose it on LAN/WAN, explicitly:
sshd --lan # bind all NICs; refuses to start if ~/.ssh/authorized_keys is empty
Z2_SSHD_LAN=1 sshd # also works via env
\\tsclient\<name>-J) per destination — they apply to the shell, SFTP, every attached service and resident tunnels alike — manual forwarding in both directions (-L / -R) that can keep running after the Connections tab is closed, and a built-in sshd (dropbear) that binds to localhost only by default.z2-* command-line helpers follow the language setting, so the help text, usage lines and messages you get in the terminal are localized too. Both bodies of text are keyed by language code, so further languages drop in without touching the code that uses them; anything not translated yet falls back to English. ⚠ The keyboard is a separate matter: no Chinese input method is bundled, so type Chinese with your OS input method.reading /candidate/), so names and private abbreviations convert from the first keystroke.z2-noti (read the notifications on screen; read-only) / z2-notify / z2-toast / z2-share / z2-open / z2-img (draw a picture straight in the terminal) / z2-clip / z2-battery / z2-vibrate / z2-say / z2-torch / z2-media / z2-volume / z2-sensor / z2-intent / z2-state / z2-screen (stop the screen turning off by itself, for a while) / z2-usb / z2-tile (put a macro on a quick-settings tile; 12 slots) / z2-icon (draw the status-bar and tile icons yourself) / z2-alarm / z2-macro / z2-session (drives the app's own tabs; attach stays connected to one and types in it) / z2-server (start/stop a registered resident server).name=$(z2-ask "Branch name?") takes the answer from a notification reply field (answerable from the shade without opening the app; no answer means a non-zero exit, so "give up" is expressible).z2-when <trigger> run <cmd> auto-runs a script on Android events: charge start/stop, battery crossing a level, a time (daily / once / every N / cron), Wi‑Fi connect/disconnect, a usable connection appearing/going away or the link in use switching (net:online / net:mobile — mobile data counts too), the device booting (boot), something being shared to it from another app (share:ext=pdf …), an incoming SMS (incl. OTP code extraction), a sensor (shake / light threshold / proximity), an arriving notification (notify:otp extracts the code; independent of whether notifications are logged), any device event by name (event:headset_plugged and ~20 more; z2-when events lists them), a file appearing in, being rewritten in or leaving a folder (file:new=… / file:changed=… / file:deleted=…), a Bluetooth device connecting or disconnecting (bt:connect=<name>), an app coming to the front or being left (app:open=<app>), the battery temperature (battery:temp>45), or today's steps reaching a goal (steps:reach=8000). In the editor, triggers are picked as sentences from rows (Time, Power, Connections, Apps & notifications, Device), and the reason a trigger cannot run (detection off, permission missing) is shown right there. Rules can be narrowed with filters (if=ssid=Home / cooldown=1h / between=22:00-07:00 / days=mon-fri — they work the same for every trigger, and skipped runs stay in the log as skip:). Rules are plain text under ~/.z2term/when/ (git-syncable) and survive reboots without opening the app. The Automation tab (📜) lists them with on/off toggles, run logs and a ▶ run-now that skips the trigger, plus a kill switch that pauses every rule and a list of recent fires (z2-when pause / resume / fired in the terminal).z2adb connects to the device's own wireless debugging over localhost. No PC, USB, or root.z2-session attach keep running while locked, so nothing left working overnight is broken.z2help (or z2term) prints a categorized cheat sheet of every z2* helper, and every command explains itself with --help (e.g. z2-tile --help); z2version shows the app version and the engine the tab is really running on.z2doctor — one command that answers "why isn't it working?": version, engine, free space, every permission the app needs, detection and automation state. Each NG line carries the next step, and the end is a short report you can paste into an issue (--share / --clip). SSIDs, IPs and host names are left out on purpose.z2scan self audits this device/localhost (open ports, sshd config, SSH key perms, world-writable/SUID, PATH) with no external tools; z2scan net/host/cve wrap nmap/lynis/trivy on localhost (a remote target requires explicit opt-in). Results stay local.~/z2term-log/, so they open straight from the shell or from other apps. By default colors and screen control codes are stripped so the result reads as plain text.~ on your home screen (tail or head, your choice; scroll inside to read further back, long lines wrap, error lines are coloured).192.168.x.x and friends) and anything over Wi-Fi keep working, and other apps are untouched (reading the device-wide figure asks for the "usage access" permission once).~/z2term-inbox/) is inserted on the terminal's input line — never executed.| MBassador 1.3.2 |
| MIT |
| bennidi/mbassador |
| SLF4J API 2.0.18 | MIT | qos-ch/slf4j v2.0.18 |
| Bouncy Castle 1.85.2 | MIT | bcgit/bc-java r1rv85v2 |
| XZ for Java | 0BSD | Tukaani XZ for Java |
| Guava ListenableFuture 1.0 | Apache-2.0 | google/guava |
| JetBrains Java Annotations 23.0.0 | Apache-2.0 | JetBrains/java-annotations |
| Fira Code / IBM Plex Mono / JetBrains Mono | OFL-1.1 | tonsky/FiraCode / IBM/plex / JetBrains/JetBrainsMono |
Z2 Mono (made for this app; generator in scripts/z2-mono/) | OFL-1.1 | this repository |
SKK-JISYO.L (source of the bundled dictionary z2dict.txt) | GPL-2.0-or-later | skk-dev/dict |
IPADIC (mecab-ipadic 2.7.0-20070801; source of kkc_lex.tsv / kkc_matrix.bin) | NAIST license | taku910/mecab |
Japanese Wikipedia (source of the co-occurrence data kkc_colloc.bloom) | CC BY-SA 4.0 | jawiki dumps |