- Java 17 required. Build fails with older versions.
- NDK
30.0.14904198— native C code interminal-emulator,termux-shared, andappmodules. CMake3.31.6. - Build:
./gradlew assembleDebug - Tests:
./gradlew test(unit tests only; no instrumented tests in CI) - No lint, detekt, ktlint, or formatter is configured. The only CI quality gate is
./gradlew test. - Gradle 9.7.1, AGP 9.4.1, Kotlin 2.4.20. Daemon enabled, parallel builds capped at 2 workers.
- The file manager is its own module; its unit tests run via
./gradlew :filemanager:test.
app → termux-shared → terminal-view → terminal-emulator
└─→ filemanager → termux-shared
| Module | Package | Purpose |
|---|---|---|
terminal-emulator |
com.termux.terminal |
VT100/xterm emulation engine, JNI pty, zero internal deps |
terminal-view |
com.termux.view |
Android View rendering for the terminal |
termux-shared |
com.termux.shared |
Shared logic: settings, file utils, error system, crash handling, constants |
filemanager |
com.estrin217.filemanager |
Reusable file manager library: FileOperationsHelper, FileSortOption, Compose FileManagerScreen/FileManagerViewModel — Java + Kotlin (Compose), self-contained string resources |
app |
com.termux |
UI activities, services, app entry point — Java + Kotlin (Compose) |
terminal-viewexposesterminal-emulatorviaapi()(transitive). Don't change this toimplementation()without understanding the impact on consumers.filemanagerdepends ontermux-shared(forTermuxConstants). The host wiring stays inapp:FileManagerSessionHosthostsFileManagerScreenas a session tab, and the legacyFileManagerComposeActivity(opened from the Compose session tab) wires storage permissions,FileProvider, and the Compose theme.- Modify
terminal-emulatorfor emulation bugs. Modifyappfor UI/Activity bugs. Modifytermux-sharedfor cross-cutting concerns.
- Library modules (
terminal-emulator,terminal-view,termux-shared) are pure Java. Do not add Kotlin files there. The only Kotlin library isfilemanager(Java helpers + Kotlin Compose UI). appmodule uses Kotlin for the Jetpack Compose UI layer (com.termux.terminal.composepackage). Existing activities/services remain Java.- Hungarian notation (
mprefix:mTermuxService,mIsVisible) is used in both Java and Kotlin — keep this when adding new code. LOG_TAG: every class definesprivate static final String LOG_TAG = "ClassName";at the top (Java) orcompanion object(Kotlin).finalclasses for concrete implementations (e.g.,TerminalView,TerminalSession).- Javadoc/KDoc on all public methods with
@param/@return. Use{@link ClassName}for cross-references. - Constants in
TermuxConstants.java(~1357 lines) — all string constants, paths, intent actions, and extras live here. Add new constants here, not scattered across classes. - Indent: 4 spaces (2 for YAML). LF line endings. UTF-8. See
.editorconfig.
- Compose stack: BOM (
2026.09.00), Material3, ViewModel, coroutines, Coil (imágenes remotas), commons-compress (rootfs extraction). No hay Ktor: el HTTP del instalador esHttpURLConnectiona pelo. - Entry point:
TermuxComposeActivity.kt— the main Compose activity. TerminalViewRegistryholds the activeTerminalViewreference for Compose callbacks.- New Compose UI goes in
com.termux.terminal.compose. New settings screens go incom.termux.terminal.compose.settings. - The
filemanagermodule also uses Compose (Material3) for itsFileManagerScreen; it does not host activities — the app wires the theme, permissions, andFileProvider. - Session tabs are polymorphic:
TermuxSessionUiModelis a sealed type (Terminal= pty session,FileManager= UI-only session). TheFileManagerSessionHostcomposable hostsFileManagerScreenas a tab with a per-sessionFileManagerViewModelkeyed by session id. Closing a file-manager tab never touchesTermuxService. The file manager can open a terminal in the current directory viaonOpenInTerminal(nav-row icon + More-menu item), wired in the app toTermuxComposeActivity.openTerminalIn().
- Return
Errorobjects, don't throw.nullmeans success:Error error = TermuxFileUtils.isTermuxFilesDirectoryAccessible(ctx, true, true); if (error != null) { Logger.logErrorExtended(LOG_TAG, "Failed\n" + error); return; }
Errnoclass defines error codes (ERRNO_SUCCESS,ERRNO_CANCELLED,ERRNO_FAILED). UseErrno.getError()factory methods.- Try/catch is targeted, not blanket. Catch specific exceptions (
IOException,BadTokenException). Log viaLogger, show Toast to user, set state flag (e.g.,mIsInvalidState = true). - Crash handling:
CrashHandler(uncaught exceptions) → writes to crash log file → notifies app via broadcast. Set inTermuxApplication.onCreate(). - Logging: Use
com.termux.shared.logger.Logger, notandroid.util.Logdirectly. Logger handles Android's 4068-byte logcat limit by splitting long messages.
- Client Interface Pattern: Interfaces define contracts (
TerminalSessionClient,TerminalViewClient). Base classes provide no-op defaults (TermuxTerminalSessionClientBase). Concrete implementations inappextend bases. Follow this pattern for new callbacks. - Service lifecycle:
TermuxServiceoutlivesTermuxComposeActivity. Activity re-binds on rotation/restart. Don't store activity references in the service — use the client interface. - Static utility classes for stateless helpers (
TermuxUtils,TermuxThemeUtils,DataUtils).
- targetSdk 28 is intentional — raising it triggers scoped storage and other restrictions that break file access model.
- minSdk 24 — proot uses
getifaddrs(Bionic API 24+). Native code is compiled against android-28. - ABI splits are enabled by default for debug builds (
arm64-v8a+ universal). Controlled byTERMUX_SPLIT_APKS_FOR_DEBUG_BUILDSenv var. - arm64-v8a only — proot binary (loader + AArch64 assembly) is hardcoded for arm64. No other ABIs are supported at runtime.
- proot build pipeline — CMake builds a multi-stage proot binary (loader → strip → objcopy → loader-info → final proot), staged to
app/src/main/assets/arm64-v8a/proot.merge.*Assetstasks depend onbuildCMaketo ensure the binary is in the APK on first build. - Debian rootfs downloads at first launch (not build time) via
DebianInstaller.javawith streaming SHA-256 verification. The olddownloadBootstrapsGradle task was removed. - Shared UID (
com.termux) — all Termux apps share a Linux UID. APKs must be signed with the same key. - JitPack NDK (
29.0.14206865viaJITPACK_NDK_VERSIONenv) differs from local/CI NDK (30.0.14904198). This is expected — JitPack uses an older NDK. - Commit convention: Conventional Commits with capitalized leading types:
Added,Changed,Deprecated,Removed,Fixed,Security. - Version name must follow semver (
major.minor.patch). Validated inapp/build.gradle.kts. Use./gradlew :app:versionNameto print the current version.
- Package:
com.estrin217.terminal. App name: "Terminal". Not affiliated with the Termux team. - README and docs are in Spanish (repository language). Code comments are in Spanish or English.
- This fork bundles proot + Debian rootfs instead of the upstream Termux bootstrap packages.
- Al empezar, lee
MEMORY.mdpara conocer el estado del proyecto y las decisiones tomadas. - Al terminar una tarea, actualízalo: estado actual, decisiones importantes (con su porqué) y errores a evitar.
- Mantenlo breve (máximo ~50 líneas): resume o elimina lo que ya no aporte.
- Si algo se convierte en una regla permanente, propón moverlo a
AGENTS.mden lugar de dejarlo en la memoria. - No guardes nunca datos sensibles (claves, tokens, datos personales).
- ✅ Siempre: actualizar
MEMORY.mdal terminar cada tarea.
- Lee
docs/constitution.mdy la spec activa (specs/NNN-*/) antes de tocar código.