Skip to content

Architecture Overview

djunekz edited this page Apr 10, 2026 · 2 revisions

Architecture Overview

Technical explanation of how Termux App Store works internally.


High-Level Overview

+--------------------------------------------------+
|                Termux App Store                  |
+------------------------+-------------------------+
|      TUI Interface     |      CLI Interface      |
|   (Textual / Python)   |  (argparse / shell)     |
+------------------------+-------------------------+
|                  Core Engine                     |
|  Package Scanner    Metadata Parser              |
|  Version Checker    Dependency Resolver          |
|  Status Badge       Self-Healing Path Resolver   |
+--------------------------------------------------+
|                 Build System                     |
|             build-package.sh                     |
|  Download Source    SHA256 Verify                |
|  apt-get deps       Build and Install            |
|  Progress Log       Error Handling               |
+--------------------------------------------------+
|              Package Repository                  |
|             packages/<n>/build.sh                |
+--------------------------------------------------+

Startup Flow

termux-app-store (binary or Python)
        |
Self-Healing Path Resolver
  Locate the packages/ directory from multiple candidate paths
        |
Package Scanner
  Scan all subdirectories in packages/
  Read each build.sh
        |
Metadata Parser
  Extract: NAME, VERSION, DESCRIPTION, DEPENDS, HOMEPAGE
        |
Version Checker
  Compare TERMUX_PKG_VERSION with the installed version
        |
Status Badge Generator
  Assign: NEW / UPDATE / INSTALLED / UNSUPPORTED
        |
TUI / CLI Renderer
  Display results to the user

Install Flow

termux-app-store install baxter
        |
Read packages/baxter/build.sh
        |
Dependency Check
  For each item in TERMUX_PKG_DEPENDS:
    Check if already installed
    If not -> apt-get install
        |
Download Source
  curl -L TERMUX_PKG_SRCURL -> source.tar.gz
        |
SHA256 Verification
  sha256sum source.tar.gz == TERMUX_PKG_SHA256?
  Mismatch -> abort
        |
build-package.sh
  Extract -> Install -> Package as .deb -> Install .deb
        |
Post-install Verification
  Confirm binary is accessible in PATH
        |
Done

File and Folder Structure

termux-app-store/
|
+-- termux-app-store.py      Entry point (Python/Textual)
|
+-- packages/                Package repository
|   +-- baxter/
|   |   +-- build.sh
|   +-- zora/
|       +-- build.sh
|
+-- build-package.sh         Main build engine
+-- install.sh               TAS installer
+-- uninstall.sh             TAS uninstaller
+-- tasctl                   TAS management CLI
+-- termux-build             Validation and creation tool
+-- guidebook.py             Interactive bilingual guidebook
|
+-- template/
|   +-- build.sh             Template for new packages
|
+-- tools/                   Internal helper scripts
|   +-- termux-build-init.sh
|   +-- termux-build-lint.sh
|   +-- termux-build-check-pr.sh
|   +-- termux-build-doctor.sh
|   +-- termux-build-suggest.sh
|   +-- termux-build-explain.sh
|   +-- termux-build-template.sh
|   +-- termux-build-guide.sh
|   +-- termux-build-create.sh
|
+-- ci/                      CI pipeline scripts
+-- .github/
    +-- workflows/           GitHub Actions
    +-- ISSUE_TEMPLATE/
    +-- PULL_REQUEST_TEMPLATE.md

Self-Healing Path Resolver

TAS locates its packages/ directory even when moved or renamed:

SEARCH_PATHS = [
    script_dir / "packages",
    script_dir / ".." / "packages",
    home / "termux-app-store" / "packages",
    prefix / "lib" / ".tas" / "packages",
    "/data/data/com.termux/files/usr/lib/.tas/packages",
]

for path in SEARCH_PATHS:
    if path.exists():
        return path

Metadata Parser

Reads variables from build.sh statically, without executing the script:

def parse_build_sh(path):
    metadata = {}
    with open(path) as f:
        for line in f:
            match = re.match(r'TERMUX_PKG_(\w+)=\"?([^\"]*)\"?', line)
            if match:
                key = match.group(1)
                value = resolve_vars(match.group(2), metadata)
                metadata[key] = value
    return metadata

No shell execution means no side effects and no security risk.


Status Badge Logic

def get_status(pkg_name, pkg_version, depends):
    for dep in depends:
        if not is_available_in_termux(dep):
            return "UNSUPPORTED"

    installed = get_installed_version(pkg_name)

    if installed is None:
        if days_since_added(pkg_name) < 7:
            return "NEW"
        return "AVAILABLE"

    if version_compare(pkg_version, installed) > 0:
        return "UPDATE"

    return "INSTALLED"

Concurrency Model

  • The UI runs in the main async event loop (Textual)
  • Builds run in background threads
  • Thread-to-UI communication uses call_from_thread()
  • Only one install is allowed at a time to prevent state corruption

CI/CD Pipeline

Push or PR to master
        |
        +-- GitHub Actions (build.yml)
        |       |
        |       +-- Lint changed packages
        |       +-- Validate build.sh format
        |       +-- CLI behavior checks
        |       +-- Code coverage (Codecov)
        |
        +-- Auto-update package index (update_index.yml)

Technology Stack

Component Technology
TUI Framework Textual (Python)
CLI Python argparse
Build Engine Bash shell script
Binary Packaging PyInstaller / Nuitka
Package Manager pip (PyPI)
CI/CD GitHub Actions
Code Coverage Codecov
Package Validation termux-build (Bash)

See Also

Clone this wiki locally