Table of Contents
- 🧭 Quick overview
- 🗂️ Format & parsing basics
- 🧾 Main package fields
- Package identity & description
- ⚖️ API checks (ensure compatibility)
- 🧩 Runtime requirements (api.require)
- 🔗 Include other packages (include)
- ⚙️ Process / service fields (process.*)
- 🧰 config — run commands at import time
- 🖥️ mod — Looping commands
- 🧭 command — register shell commands / aliases
- file — create files in /home/ 🗃️
- 🐚 shell.* — build a shell subcommand table
- ✂️ Full minimal Application template (copy/paste)
- 📝 Practical tips
- 🔍 What OpenTTY logs / does on failure
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
🧭 Quick overview
When OpenTTY imports a package file whose content begins with a [ Config ] header, it parses that file into key/value properties and executes these steps (in roughly this order):
- API checks —
api.version,api.match,api.error. If a required API version or match rule fails, the package can trigger an error action. - Runtime dependency checks —
api.require. If the package expects features not available (for examplelua,canvas,devicefs), import can fail. - Includes —
includecan list other packages (comma-separated). Each included entry is imported recursively. - Process / service setup —
process.*keys can start background processes, bind ports, etc. - Run package configuration —
configis executed as a command (so it can set up environment, create files, register aliases, etc.). - UI / MIDlet modules —
modtogether withprocess.namemay register a GUI screen or service. - Commands & Files —
command/fileentries let the package create shell aliases and write files into/home/. - Shell registration —
shell.name,shell.args, and optionalshell.unknownbuild a shell-command table that the main shell will use to dispatch subcommands.
Use the sections below for each field, how to configure it, and small examples.
🗂️ Format & parsing basics
- A package is a plain text file parsed as key/value pairs (simple
key=valuelines).importScript()usesparseProperties()to build a property map from the file. Keys are referred to asPKGentries in OpenTTY code. - Several keys accept comma-separated lists (for example
include,command,file, andshell.args). - Values can be other package keys (the loader will later evaluate environment substitution via
env()at runtime), so you can reference one field from another in your package text.
🧾 Main package fields
Below are the fields you listed plus other commonly-used keys. For each key: what it does, expected value, and a small example.
Package identity & description
name— friendly app name (displayed byaboutand UI).version— app version.description— short description displayed to the user.
Example
name=MyTool
version=1.0
description=A tiny helper app
(When about is run, OpenTTY prints name version and description if present.)
⚖️ API checks (ensure compatibility)
-
api.version— version string the package expects (compared to OpenTTY’s$VERSION). -
api.match— matching mode forapi.version. Accepted modes (seen in the loader) include:exact-prefix(default) — checks that OpenTTY’s version starts withapi.version.minimum/maximum— numeric comparisons on version parts.exact-full— exact equality.
-
api.error— command string to run if the API compatibility check fails (e.g.,warn Package requires newer OpenTTY).
Behavior: If the version check fails, the loader runs the api.error command (or true if none) and returns an error status; the package import stops.
Example
api.version=0.6
api.match=minimum
api.error=warn This package requires OpenTTY 0.6+
🧩 Runtime requirements (api.require)
api.require— comma-separated list of runtime capabilities the package needs (examples used by OpenTTY:lua,canvas,devicefs).- If any required capability is missing, import fails (the package can detect missing features and abort).
Example
api.require=lua,devicefs
🔗 Include other packages (include)
include— comma-separated list of other package sources (strings that will be passed togetcontent()and imported). The loader imports each included file before continuing with the main package startup. This is useful for shared libraries or dependencies.
Example
include=/lib/shared.conf,/lib/graphics.pkg
⚙️ Process / service fields (process.*)
These control running a background process or binding a port for the package.
process.name— a logical name for the process to register in OpenTTY’s process table (used forps, backgrounding, and formodscreens). If present, the loader callsstart(process.name, ...)to register a process.process.exit— command to run when the process should exit (registered as the “exit” action for that process). Used by thestart()call.process.type— (not always required) type tag for the process (used by the package if it wants to categorize itself).process.port— if provided, the loader will attempt to bind that port and spawn abindcontroller for the package; useful if the package exposes a network service. If the port is already in use, import warns and fails with a specific error.process.db— optional extra argument passed when binding a port (used by the package to include a DB or mode string when handling incoming commands).
Example
process.name=my-service
process.exit=stop my-service
process.port=1337
process.db=sqlite
Behavior note: if process.port is present, OpenTTY checks session availability and then starts a bind thread that listens on the port and forwards incoming text to the package.
🧰 config — run commands at import time
config— a command (or chain of commands) executed immediately when the package is imported. This is where packages perform setup tasks, register aliases, write runtime state, or create files. The loader will execute this and if it returns a non-zero status the import fails.
Example
config=echo Installing...; touch /home/app-file.txt
🖥️ mod — Looping commands
mod— Run the value of this field while the generated process of the Application is alive. Requiresprocess.namefield.
Example
mod=echo "Until process be killed or an error have been occurred."
🧭 command — register shell commands / aliases
command— comma-separated list of names to expose as shell commands (each name must also be a key in the package whose value is the command string that will run). The loader creates shell aliases from thosecommandnames and their corresponding package values. If a referenced command key is missing, an error log is recorded.
Example
command=hello,goodbye
hello=echo "Hello, world!"
goodbye=echo "Goodbye!"
Behavior: after import, typing hello in the OpenTTY shell will run the configured command.
file — create files in /home/ 🗃️
file— comma-separated filenames. For every name listed OpenTTY will look for a package key with that name and write the corresponding value into/home/<filename>in the record store. If the content key is missing, a log warning is generated.
Example
file=README,example.conf
README=Welcome to MyTool!
example.conf=option1=1
After import the user can cat /home/README (or get README) to view the file.
🐚 shell.* — build a shell subcommand table
Packages can register a custom shell entry (a table of subcommands) that the interactive shell uses.
shell.name— the name under which this shell table will be registered (for examplegitormytool).shell.args— comma-separated list of property names that map to arguments/subcommands. For eachNAMEinshell.args, the loader fetches the package propertyNAMEand stores the value in a table. Ifshell.unknownexists it’s saved too and used as fallback. The table is added to the globalshellmap — the interactive shell will detect it and routemytool subcmdto the table’s stored command.
Example
shell.name=mytool
shell.args=start,stop,status
start=/home/mytool/start.sh
stop=/home/mytool/stop.sh
status=/home/mytool/status.sh
shell.unknown=echo Unknown subcommand
Behavior: typing mytool start will run the command stored in the table for start; if the subcommand is not found and shell.unknown exists that fallback command is executed.
✂️ Full minimal Application template (copy/paste)
Use this as a starting point — put it at the top of your package text:
[ Config ]
name=MyApp
version=0.1
description=A short description
api.version=1.16
api.require=lua
api.match=minimum
api.error=warn This package requires OpenTTY 1.16+ and Lua Runtime
include=/lib/common.pkg
process.name=myapp
process.exit=true
process.port=1337
process.db=execute
config=echo Installing...; true
command=start,stop
start=echo "Starting..."
stop=echo "Stopping..."
file=README
README=This is MyApp.
shell.name=myapp
shell.args=start,stop,status
shell.unknown=echo Unknown subcommand
Notes
configsupports any shell-style commands recognized by OpenTTY (the loader executes it via the shell engine).includeentries are imported before the rest of the package is finalized; use them for shared dependencies.
📝 Practical tips
- Test API requirements first — if your package needs optional features (Lua, canvas, or file access) declare them in
api.requireso import fails with a clear message instead of silently misbehaving. - Use
configto create runtime files (via the shell), or usefile=to provisioning persistent/home/files from properties. The loader writes thefileentries into/home/automatically. - Avoid port conflicts — if you set
process.port, the loader checks sessions and will fail the import when the port is unavailable (it logs a warn and returns a port-in-use error). - Shell subcommands —
shell.name+shell.argsis the recommended way to expose grouped commands (likegit push) to the user shell. Provideshell.unknownto give a friendly fallback.
🔍 What OpenTTY logs / does on failure
- If
api.versioncheck fails: the loader runsapi.error(if provided) and aborts import with an error return. - If a
includeimport fails: the entire import stops and returns the include’s status. - If
process.portis already in use the loader warns and aborts the package start.