Package Specification
This section defines the formal specifications for TOS 7 application packages. All applications must comply with this specification.
Application Lifecycle
TOS 7 applications follow a clearly defined lifecycle:
Install ──► Configure ──► Start ──► Running
│ │ │ │
│ │ │ ├── Stop ──► Stopped ──► Start (Restart)
│ │ │
│ │ └── Crash ──► Auto-restart (if configured)
│ │
│ └── Upgrade ──► Stop ──► Install New Version ──► Migrate ──► Start
│
└── Uninstall ──► Stop ──► Cleanup ──► Remove
Deb Application Lifecycle Stages:
| Stage | Trigger | Script/Operation | Expected Behavior |
|---|---|---|---|
| Before Install | dpkg -i | DEBIAN/preinst | Create user, check prerequisites, create directories |
| Install | dpkg -i | Package extraction | Files deployed according to the packaging specification (see Chapter 8); the application sees the directory as /usr/local/<appid>/, and the platform resolves it to /Volume<N>/@apps/<appid>/ on the user-selected data volume |
| After Install | dpkg -i | DEBIAN/postinst | Set permissions, enable service, start service |
| Start | systemctl start | systemd / init.d | Application process starts |
| Stop | systemctl stop | systemd / init.d | Application process gracefully stops |
| Before Uninstall | dpkg --remove | DEBIAN/prerm | Stop service |
| After Uninstall | dpkg --remove | DEBIAN/postrm | Clean up user, data, residual files |
| Upgrade | dpkg -i (new version) | prerm → Upgrade → postinst | Stop old version, install new version, migrate data, start |
Docker Application Lifecycle Stages:
| Stage | Trigger | Operation | Expected Behavior | Additional Notes |
|---|---|---|---|---|
| Install | App Center (user clicks "Install" button) | Pull image, create volumes | Image available, data directories created | Platform automatically executes the installation process; no additional developer intervention required |
| Start | App Center (user clicks "Start" button) / docker-compose up | Start container | Service accessible | Users can also manually start via command line, consistent with platform operation logic |
| Stop | App Center (user clicks "Stop" button) / docker-compose down | Stop container | Service stopped, data retained | Only stops the container process; mounted data volumes are not deleted |
| Upgrade | App Center (user clicks "Update" button when a new version is available) | Pull new image, rebuild container | Zero-downtime or brief downtime | It is recommended that applications support smooth upgrades to avoid data interruption |
| Uninstall | App Center (user clicks "Uninstall" button) | Remove container, optionally clean up volumes | All resources released | Users can choose whether to retain data volumes to avoid accidental data deletion |
Note: "App Center" refers to the built-in application management interface of the TOS system. Install/start/stop/upgrade/uninstall operations performed by users through this interface will trigger the corresponding lifecycle processes. In the current TOS version, upgrade is not supported for Docker applications — to move a Docker application to a new version, users must uninstall and then reinstall it (see Chapter 9 · Docker Development).
Version Number Specification
Platform behaviour (current): The Developer Platform does not validate the version number. Non-standard formats, duplicate versions, and version numbers that do not increase are not rejected. The platform simply reads the version field from config.ini and displays it in the App Center. The rules below are therefore recommendations for compatibility, not submission requirements.
Why the format still matters — update detection:
The TOS App Center currently determines whether an update is available by comparing version numbers numerically, segment by segment. This is a functional dependency rather than a submission rule:
- If the new version is numerically greater than the installed one, users see the update prompt.
- If it is not greater (equal, lower, or not numerically comparable such as
v2or1.0.0-rc1), the update may not be detected — the package is still accepted, but it may never reach existing users.
Recommended format:
| Rule | Description |
|---|---|
| Characters | Digits (0-9) and dots (.) are recommended. Letters and hyphens (e.g. v1.2, 1.2.3-beta) cannot be compared numerically and may break update detection |
| Segments | 1 to 3 numeric segments (e.g., 1, 1.2, 1.2.3) |
| Segment length | No per-segment length limit; each segment can contain any number of digits |
| Total length | No length limit is enforced. Keeping the version string short (the previous limit was 20 characters) is still recommended |
| Beta versions | Use the "beta": true field in config.ini to mark beta releases. Suffixes such as -beta / -rc / -alpha are not rejected, but they break numeric comparison |
Version ordering (comparison rules):
Versions are compared segment-by-segment as numbers, from left to right:
| Rule | Description |
|---|---|
| Numeric comparison | Each segment is compared as an integer (leading zeros are ignored, e.g., 01.2 equals 1.2) |
| Missing segments | Missing segments are treated as 0 (e.g., 1.2 equals 1.2.0; 1 equals 1.0.0) |
| Comparison result | The first segment where values differ determines the order |
Version consistency across files:
The platform does not compare the version numbers inside a package against each other, and it does not require them to match. The version is read from config.ini.
| Location | Field | Read by |
|---|---|---|
config.ini | version | The Developer Platform and the TOS App Center — this is the version displayed to users |
DEBIAN/control (Deb apps only) | Version | The Debian package manager (dpkg) — this is the version recorded by the system |
- Still recommended: keep them consistent. A mismatch causes no rejection, but it does cause a confusing installation — users would see one version in the App Center while
dpkg -lreports another, which complicates upgrades and support. - Keep
DEBIAN/controlVersionnon-decreasing. At thedpkglevel, installing a package whoseVersionis lower than the installed one is refused (downgrade protection). This is package-manager behaviour and is independent of the Developer Platform. - Version source: the version is not entered manually on the Developer Platform, and the GitHub/Gitee Release tag is not used to determine it — it always comes from the
versionfield inside the package you select. - Rollback: the platform does not roll an application back to a smaller version number automatically. If a rollback is needed, submit a rollback request on the Developer Platform (see Chapter 17).
Beta Version Management:
Beta status is controlled by the beta flag in config.ini, not by the version string:
| Release Type | config.ini Entry | Platform Display |
|---|---|---|
| First beta | "version": "1.0.0", "beta": true | 1.0.0 (Beta) |
| Second beta | "version": "1.0.1", "beta": true | 1.0.1 (Beta) |
| Stable release | "version": "1.0.2", "beta": false | 1.0.2 |
- Version suffixes such as
-beta,-rc, or-alphaare not rejected, but they break numeric comparison. Use the"beta": truefield instead so beta builds are still recognised as new versions by beta users. - Multiple beta versions are distinguished by increasing the numeric part (recommended: increment the patch segment).
- When promoting a beta to stable, set
"beta": false. The version number can remain unchanged; if you do increase it, beta users are also offered the update. - A stable release whose version number is lower than a previously submitted beta build will not be offered to users still on that beta build as an update.
- See Appendix M - Beta App Management for details
Release Asset Naming Specification
When uploading application packages to GitHub/Gitee Releases, use the recommended names below. What the platform actually relies on is the file extension: a .deb file is treated as a single Deb package, and a .tar.gz archive as a dual-package Deb archive or a Docker package (matching the application type you declared when creating the application).
The platform does not validate the package file name and no longer checks <app_id> or <platform> against it. The version is read from the version field inside config.ini; it does not need to appear in the file name, and the file name is no longer matched against any version. Package identity is verified after the download and parsing, by comparing config.ini (id, platform, and package type) with the application information you entered on the Developer Platform.
| Application Type | Package Format | Recommended Name | Example |
|---|---|---|---|
| Deb (Single Package) | .deb file | <app_id>_<platform>.deb | myapp_x86_64.deb |
| Deb (Dual Package) | .tar.gz archive | <app_id>_<platform>.tar.gz | myapp_x86_64.tar.gz |
| Docker Application | .tar.gz archive | <app_id>.tar.gz | myapp.tar.gz |
Field Definitions (recommended, not enforced):
<app_id>: Recommended to match theidfield inconfig.ini(case-sensitive)<platform>: Recommended to match theplatformfield inconfig.iniand be one of the two supported values (x86_64oraarch64). It does not accept multiple values orall. For multi-architecture support, each target architecture must be submitted as a separate build. The platform does not read the architecture from the file name — it verifies the architecture after parsing the package.
Release tag: the GitHub/Gitee Release tag is not used to determine the version and does not have to match config.ini.version. Any tag is accepted; naming it after the version (e.g. v1.0.0 or 1.0.0) is recommended for readability only.
Upgrades
Deb Application Upgrades:
- During upgrade,
preinstreceives$1 = "upgrade"parameter postinstreceives$1 = "configure"parameter, with$2being the old version number- Use
$2to detect the old version and perform data migration - Never delete user data during the upgrade process; only modify configuration formats or migrate data structures
- Users store persistent business data in the
/Volume<N>/<appid>/shared folder, which is created by the application viater_share_add. The platform will not delete or overwrite user data in this shared folder during application upgrades or reinstallation - Runtime data (caches, temporary files) is stored in
/usr/local/<appid>/data/and can be safely regenerated - It is recommended not to store data in system common directories such as
/etc,/var,/usr/bin, as these directories may be overwritten by system updates or application upgrades, leading to data loss
# Example: postinst with migration logic
case "$1" in
configure)
if [ -n "$2" ]; then
# Upgrading from version $2
if dpkg --compare-versions "$2" lt "2.0.0"; then
# Migrate v1.x configuration format to v2.x
/usr/local/<appid>/bin/migrate.sh "$2"
fi
else
# Fresh install
echo "Fresh install"
fi
;;
esac
Docker Application Upgrades:
- Pull new image tags
- Rebuild containers using existing volume mounts
- Preserve data across upgrades through persistent volumes (the platform resolves them to the application data root
/Volume<N>/DockerAppData/<appid>/) - Include migration logic in the application entry script if needed
- Docker applications do not use TNAS shared folders: no shared folder is created for them, and all persistent business data stays in the container's volume mounts
Compatibility Matrix
| TOS Version | Base System | glibc | Python3 | Docker | Node.js |
|---|---|---|---|---|---|
| TOS 7.0 | Ubuntu 22.04-compatible | 2.35 | 3.10 | 20.10+ | 18.x |
| TOS 7.x | Ubuntu 22.04-compatible | 2.35 | 3.10 | 20.10+ (or higher) | 18.x (or higher) |
Node.js versions are for reference within Docker containers only. Deb applications must not directly depend on them.
Applications must declare the minimum TOS version requirement via the low_version field in config.ini. The platform will automatically filter out incompatible devices.
TOS 7.x Minor Version Compatibility: The TOS 7.x minor version series (including 7.1 and above) will maintain ABI/API compatibility for core dependencies (glibc/Python3/Docker/Node.js), compatible with the Ubuntu 22.04-compatible root filesystem. Applications developed for TOS 7.0 will run without additional adaptation.
TOS 7 Minor Version Compatibility:
- The
low_versionfield must specify the minimum required TOS version - When submitting updates, test on the latest TOS 7 minor version
Case Sensitivity Specification
TOS employs a root filesystem compatible with Ubuntu Linux, and the filesystem is strictly case-sensitive. All applications must follow the rules below:
| Element | Rule |
|---|---|
| Filenames | Strictly match case. config.ini ≠ Config.ini ≠ CONFIG.INI |
| Directory names | Strictly match case. /images/icons/ ≠ /Images/Icons/ |
| config.ini key names | All key names must be lowercase. "version" correct, "Version" incorrect |
Application ID (id) | Strictly match case. MyApp ≠ myapp. Cannot be modified after creation |
| Systemd service name | Must strictly match, case-sensitive |
Using case variants of the same file or directory within a single application package. This causes "file not found" and "service start failure" errors on Linux.
Cross-Platform Line Ending Specification (CRLF to LF)
All scripts and configuration files running on the TOS system (Linux environment) must use LF (\n) as the line ending. Using Windows default CRLF (\r\n) line endings is prohibited.
Impact
- Script execution errors:
bad interpreter: No such file or directory - Configuration file parsing failures (e.g., systemd service files, Nginx configurations)
- Interpreter paths incorrectly recognized as non-existent binaries like
/bin/bash\r
Mandatory Requirements
- All
.sh/.py/.ini/.lang/.service/.conffiles must be converted to LF line endings before submission - Deb package build scripts must include automatic conversion logic to prevent CRLF from being introduced during the build process
Recommended Fixes
Option 1: Automatic Conversion in Build Script (Recommended)
import os
def convert_crlf_to_lf(file_path):
with open(file_path, "rb") as f:
content = f.read()
content = content.replace(b"\r\n", b"\n")
with open(file_path, "wb") as f:
f.write(content)
# Before packaging, iterate over all files that need conversion
for root, _, files in os.walk("your_app_source/"):
for name in files:
if name.endswith((".sh", ".py", ".ini", ".lang", ".service", ".conf")):
convert_crlf_to_lf(os.path.join(root, name))
Option 2: Local Development Tool Configuration
- VS Code: Click
CRLFin the bottom-right status bar, switch toLF, then save - Git Global Configuration (prevent subsequent files from being auto-converted to CRLF):
git config --global core.autocrlf input