TOML configuration guide for Tool-Tree
This guide is for Tool-Tree, the component that powers the function menu in the com.tool.tree Android app.
All page configuration files must use TOML (XML is no longer supported).
The parser lives in com.omarea.krscript.config.PageConfigReader and uses the org.tomlj:tomlj library.
A TOML configuration file describes the node tree of a page: each page is a list of nodes
(group, action, switch, picker, text, page, editor, download, resource, menu, fab) displayed in the order they appear in the file.
All nodes are declared flat at the top level of the document (dot-notation nesting like [[group.action]] has been removed) - a node that follows a [[group]] (and precedes the next one) automatically becomes a child of that group.
2. Syntax rules
2.1. Always use double brackets [[name]] for every entry
TOML does not allow mixing [name] (single brackets, single table) and [[name]] (double brackets, array of tables) for the same key at the same position - this will cause a parse error. To be safe, always use [[name]] for any entry, even if there is currently only one entry of that type. This prevents breaking the file later when you add a second entry of the same type but forget to switch the brackets.
[group] and then later declaring another [[group]] in the same file -> parse error.[[group]], [[action]], etc. for all entries.2.2. Node type = TOML table name
There is no separate type field. A node's type is determined by its TOML table name:
| Table name | Node type | Description |
|---|---|---|
group | Container | Holds child nodes - the flat entries declared after it become its children (no nesting) |
page | Sub-page | Opens another page when clicked |
action | Action | Runs a shell script |
switch | Toggle | On/off switch with get/set shell |
picker | Picker | Single/multi value selector |
text | Rich text block | Multi-row text (bold/italic/link/photo...) |
editor | File editor | Opens a file in the built-in editor |
download | Download | Downloads a file, then runs a script |
resource | Asset extraction | Extracts assets from APK (invisible) |
menu | Overflow menu | Toolbar 3-dot menu container |
fab | Floating button | FAB container on the page |
2.3. Group children = nearest preceding [[group]] (dot-notation removed)
All node types are declared as flat [[type]] entries at the top level of the document - the dotted [[group.action]] / [[subgroup.type]] style is no longer supported. A child node simply belongs to the most recently declared [[group]] above it in the file; the parser walks the document once, in line order, and assigns each entry to the current group.
[[group]]
title = "CPU"
[[switch]] # child of group "CPU"
...
[[action]] # also a child of group "CPU"
...
[[group]]
title = "Battery"
[[switch]] # child of group "Battery"
...
[[group.action]] are silently ignored - the parser only reads node tables at the top level of the document (tomlChildren() is called exactly once, on the root table, and is no longer recursive per group).[[toml]] is not a node type. It is only a marker used to recognize inline TOML output from config-sh (see section 6). If it appears in a file, the parser skips it harmlessly.2.4. Display order = position in file
Display order is always top-to-bottom by the position of the [[name]] entry in the file, regardless of node type (group, action, page, text, switch ...) - even when types are interleaved (e.g. an action, then a page, then another action). The position is read directly from the tomlj API, so there is no need for an order field.
TomlArray.inputPositionOf(index).line() to obtain the line number of each array element. If the API returns null (due to error or unsupported feature), the parser falls back to read order (seq) - it never crashes.2.5. Boolean values - 3 accepted forms
Boolean fields such as confirm, readonly, auto-off accept:
| Value | Result | Notes |
|---|---|---|
true / 1 | true | Statically true |
false / 0 | false | Statically false |
| (any other string) | Run as shell, "1" => true, otherwise => false | shell via resolveBoolOrShell() |
Example: readonly = "test -f /sdcard/lock && echo 1" - the parser runs that command, and if it returns "1" then readonly = true.
support/visible of nodes and params, show of actions), the script runs immediately during parsing. Deferred fields - switch/picker/toggle get, row support, and all *-sh dynamic strings (title-sh, desc-sh, summary-sh, warn-sh) - are queued into pending states and batched at the end (see section 20).2.6. String resource references
Any text field (title, desc, summary ...) may include a reference to the app's string resources via @string/name or @string:name. The parser resolves these automatically. If the resource is not found, the original string is kept.
[[group]]
title = "@string/group_battery_title"
[[switch]]
title = "@string/switch_fast_charge_title"
desc = "@string:switch_fast_charge_desc"
get = "getprop sys.fastcharge"
set = "setprop sys.fastcharge $state"
@string/name and @string:name point to the same resource lookup - use whichever separator you prefer, they are interchangeable.3. Node type overview
Quick reference for all node types. Click a name to jump to its detailed section.
5. [[group]] - Container for child nodes
[[group]] is a container that groups related nodes. It has no icon and is not clickable - it's just a title with a list of child nodes below it.
5.1. Group fields
| Field | Alias | Type | Default | Description |
|---|---|---|---|---|
| title | - | String | "" | Group title (displayed uppercase, grey) |
| title-sh | - | String | "" | shell Script that produces title |
| key | index, id | String | auto | Unique ID |
| support | visible | Bool|Shell | true | Hide/show the group - a hidden group ALSO hides all of its children (every entry until the next [[group]] is skipped, their shells are not run). Accepts shell too! |
5.2. Demo
[[group]]
title = "CPU"
[[action]]
title = "Optimize CPU"
desc = "Set governor to performance"
script = "echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
[[picker]]
title = "Governor"
get = "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
set = "echo $state > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
[[group]]
title = "Memory"
[[action]]
title = "Clear cache"
script = "sync; echo 3 > /proc/sys/vm/drop_caches"
5.3. Grouping rules (no nesting)
Since dot-notation was removed, groups can no longer be nested inside each other. Every [[group]] is a top-level sibling: declaring a new [[group]] closes the previous one, and all following entries belong to the new group. Entries declared before the first [[group]] are rendered directly on the page without a group header.
resource-file/resource-dir fields (see section 15) and have no desc/summary - a group is just a title + its children.6. [[page]] - Sub-page
[[page]] is not an action - it's a link to another page. Clicking it opens a new page (another .toml file, an HTML page, or another Activity).
6.1. Page fields
| Field | Alias | Type | Description |
|---|---|---|---|
| config | - | String | Path to the sub-page .toml file (relative or absolute) |
| config-sh | - | String | shell Script returning inline TOML content or a .toml file path. Auto-detected by the [[group]] header |
| html | - | String | Online HTML URL - opens in a WebView |
| link | href | String | URL opened by the system browser |
| activity | a, intent | String | Activity intent to launch (e.g. com.example.MyActivity) |
| before-load | before-read | String | shell Script run BEFORE reading the sub-page config |
| after-load | after-read | String | shell Script run AFTER reading completes |
| load-ok | load-success | String | shell Script run if load succeeds |
| load-fail | load-error | String | shell Script run if load fails |
| process | - | Bool | new true: show items one by one as they build (with progress bar) instead of waiting (see section 21) |
| lock | lock-state | String | Static lock: true/1 or the "1|message" format |
| lock-sh | - | String | shell Script to check the lock state (returns "1" = locked) |
| rows | - | Array | Rich-text rows shown below the page (see section 12) |
6.2. Demo
[[page]]
title = "App list"
desc = "Manage installed apps"
config = "pages/app_list.toml"
[[page]]
title = "Advanced settings"
desc = "Open external config file"
config = "/sdcard/Tool-Tree/advanced.toml"
config-sh returns one of two things: either a .toml file path (output ending with .toml), or inline TOML content. Inline TOML is recognized when the 1st or 2nd non-empty line of the output starts with [[group]] or the reserved marker [[toml]] - see PageConfigSh.looksLikeInlineToml(). Anything else shows an error toast.7. [[action]] - Action (runs a shell script)
[[action]] is the most common node type: clicking it shows a dialog (if it has confirm/params/warning), then runs the script and shows the output in a log dialog.
7.1. Action fields
| Field | Alias | Type | Description |
|---|---|---|---|
| script | set, setstate | String | required Main shell script. Receives $param_name env vars from params |
| lock | lock-state | String | Static lock: true/1 or the "1|message" format. When locked, the action is not clickable |
| lock-sh | - | String | shell Script to check lock dynamically (returns "1" = locked) |
| menu | - | Bool | new true: action does NOT appear in the list; instead appears as its own icon on the toolbar |
| show | - | Bool|Shell | new true (or shell): auto-open this action's dialog when entering the page (only once) |
| params | - | Array | List of input parameters - see section 8 |
| rows | - | Array | Rich-text rows shown below the item - see section 12 |
| params-rows | - | Array | Rows for the params dialog only (separate from rows which appear both in list and dialog) |
| + all fields of RunnableNode, ClickableNode, NodeInfoBase (see section 4) | |||
7.2. Demo
[[action]]
title = "Optimize CPU"
desc = "Set governor to performance"
menu = true
key = "optimize_cpu"
script = "echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
[[action]]
title = "Clear cache"
desc = "Clear system cache"
confirm = true
warn = "This will clear all app caches"
script = "sync; echo 3 > /proc/sys/vm/drop_caches"
auto-off = true
menu = true and show = true are independent: an action can be both on the toolbar (menu=true) and auto-open its dialog (show=true). When an action moves to the toolbar (menu=true), an unset key falls back to title to use as the Menu itemId.8. [[action.params]] - Input parameters
Each [[action.params]] defines one input field in the dialog shown when the user clicks an action. The parameter's value is passed to the action's script via the $param_name environment variable.
8.1. Basic param fields
| Field | Alias | Type | Description |
|---|---|---|---|
| name | - | String | required Variable name (unique within an action). Becomes $name in the script |
| title | - | String | Display label |
| title-sh | - | String | shell Script that produces title dynamically |
| label | - | String | Secondary label |
| label-sh | - | String | shell Script that produces label |
| desc | - | String | Short description |
| desc-sh | - | String | shell Script that produces desc |
| desc-on | on-desc, desc-checked | String | new Note shown SPECIFICALLY when the checkbox/switch is ON (only for type=bool/checkbox/switch) |
| desc-on-sh | on-desc-sh, desc-checked-sh | String | new shell Script that produces desc-on |
| type | - | String | Input type: text/bool/checkbox/switch/seekbar/file/folder/app/spinner/single-select/multi-select |
| value | - | String | Default value |
| value-sh | value-su | String | shell Script that fetches value dynamically (runs when dialog opens) |
| placeholder | - | String | Hint when empty |
| placeholder-sh | - | String | shell Script that produces placeholder |
| required | - | Bool | Required input |
| readonly | - | Bool|Shell | Read-only (no editing). true/1/readonly = read-only, false/0/empty = editable; any other string is stored as a shell (readonlySh) evaluated later |
| maxlength | - | Int | Max character count (type=text) |
| min | - | Int | Minimum value (seekbar) |
| max | - | Int | Maximum value (seekbar). Default Int.MAX_VALUE |
| options | - | Array | List of choices (spinner/single-select/multi-select) |
| items | - | Array of String | Shorthand choice list - each entry is "value|title" or just "value". Takes priority over options tables when both are declared |
| options-sh | option-sh, options-su | String | shell Script that produces options dynamically |
| multiple | - | Bool | Allow multiple files/options |
| separator | - | String | Value separator (multi). Default \n |
| suffix | - | String | File extension filter (e.g. "zip,apk"). Only type=file |
| mime | - | String | MIME type filter. Only type=file |
| path-home | home-path | String | Initial directory when opening file picker |
| editable | - | Bool | Allow manual path entry |
| support | visible | Bool|Shell | Hide/show the param |
| sort | - | Bool | new Move readonly params to the bottom (only effective when readonly is declared) |
| allow-no-selection | no-select | Bool | new Allow spinner to be empty (e.g. when you need to distinguish "not selected" from "first item") |
8.2. Common type values
| type | UI | Related fields |
|---|---|---|
text | Text input | value, placeholder, maxlength, required |
bool / checkbox / switch | Toggle ON/OFF | value = "1"/"0", desc-on for ON-state note |
seekbar | Slider | min, max, value |
file | File picker | suffix, mime, path-home, multiple, editable |
folder | Directory picker | path-home, multiple, editable |
app | App picker | multiple |
spinner / single-select | Dropdown single choice | options/options-sh, allow-no-selection |
multi-select | Checkbox list multi choice | options, multiple=true, separator |
8.3. Demo
[[action]]
title = "Set CPU max freq"
script = """
for cpu in /sys/devices/system/cpu/cpu*/cpufreq; do
[ "$all_cpus" = "0" ] && [ "$cpu" != "/sys/devices/system/cpu/cpu0/cpufreq" ] && continue
echo $freq > "$cpu/scaling_max_freq"
echo $gov > "$cpu/scaling_governor"
done
"""
[[action.params]]
name = "freq"
title = "Frequency (kHz)"
desc = "Enter max frequency"
type = "text"
value = "2400000"
[[action.params]]
name = "gov"
title = "Governor"
type = "spinner"
value = "performance"
[[action.params.options]]
title = "Performance"
value = "performance"
[[action.params.options]]
title = "Powersave"
value = "powersave"
[[action.params]]
name = "all_cpus"
title = "Apply to all CPUs"
type = "switch"
value = "1"
[[action.params]]
name = "cfg"
title = "Config file"
type = "file"
suffix = "conf"
8.4. Dependencies (depend-*)
A param can be hidden/shown (or switched to readonly) based on the value of another param. This is a large feature - see section 17 for details.
9. [[switch]] - On/off toggle
[[switch]] displays an ON/OFF toggle. When the user toggles it, the set script is called with the env var $state set to "1" or "0". When the page loads, the get script is called to read the current state.
9.1. Switch fields
| Field | Alias | Type | Description |
|---|---|---|---|
| get | getstate | String | required Script to read state. Returning "1"/"true" = ON. If omitted, the switch always shows OFF |
| set | setstate | String | required Script to set state. Receives $state = "1"/"0" |
| lock | lock-state | String | Static lock: true/1 or the "1|message" format |
| lock-sh | - | String | shell Script to check lock dynamically (returns "1" = locked) |
| + all fields of RunnableNode, ClickableNode, NodeInfoBase | |||
9.2. Demo
[[group]]
title = "Display"
[[switch]]
title = "Dark mode"
desc = "Enable dark UI"
get = "cmd uimode night get | grep -q yes && echo 1"
set = "cmd uimode night $([ \"$state\" = \"1\" ] && echo yes || echo no)"
[[switch]]
title = "Auto brightness"
get = "settings get system screen_brightness_mode"
set = "settings put system screen_brightness_mode $state"
get immediately when parsing each switch. Instead, all get scripts of switches/pickers are queued into pendingSwitchStates and run exactly once at the end of readConfigToml() via resolvePendingStates() - reducing N shell round-trips to 1 (see section 20).10. [[picker]] - Value selector
[[picker]] displays a current value; clicking it opens a popup to choose one (or more) values from a list. When the user confirms, the set script is called with $state = the chosen value.
10.1. Picker fields
| Field | Alias | Type | Description |
|---|---|---|---|
| get | getstate | String | required Script to read the current value |
| set | setstate | String | required Script to set the value. Receives $state |
| options | - | Array | Static options list - [[picker.options]] with title/value |
| option-sh | options-sh, options-su | String | shell Script that produces options dynamically. Each line value|title or just value |
| multiple | - | Bool | Allow selecting multiple values |
| separator | - | String | Separator for multi-select values (default \n) |
| lock | lock-state | String | Static lock: true/1 or the "1|message" format |
| lock-sh | - | String | shell Script to check lock dynamically (returns "1" = locked) |
| + all fields of RunnableNode, ClickableNode, NodeInfoBase | |||
10.2. Demo
[[picker]]
title = "Governor"
get = "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
set = "echo $state > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
[[picker.options]]
title = "Performance"
value = "performance"
[[picker.options]]
title = "Powersave"
value = "powersave"
[[picker]]
title = "Max freq"
get = "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
set = "echo $state > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
option-sh = "cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies | tr ' ' '\\n'"
[[picker.options]] and dynamic option-sh, the final list is the union of both (static options first, dynamic options appended after running the shell).11. [[text]] - Rich text block
[[text]] is a non-clickable display block containing multiple rich-text rows. Use it for notices, instructions, or inline image/gif blocks.
11.1. Text fields
| Field | Alias | Type | Description |
|---|---|---|---|
| rows | - | Array | required Rich-text rows - see section 12 |
| + NodeInfoBase fields (title, title-sh, desc, desc-sh, summary, support...) | |||
11.2. Demo
[[text]]
title = "Notice"
[[text.rows]]
text = "CAUTION"
bold = true
[[text.rows]]
text = "The actions below may affect the system."
[[text.rows]]
line = true
[[text.rows]]
text = " $ run backup --full"
monospace = true
[[text.rows]]
text = "See more at: example.com/docs"
italic = true
12. [[text.rows]] - Rich text row
This is the most common display component: used in [[text]], [[action]], [[page]], [[download]] and [[action.params-rows]]. Each row is a single line of text that can have style, icon, toggle, photo, etc.
12.1. Row fields
| Field | Alias | Type | Default | Description |
|---|---|---|---|---|
| text | - | String | "" | Text content |
| sh | text-sh | String | "" | shell Script that produces text dynamically |
| bold | b | Bool | false | Bold |
| italic | i | Bool | false | Italic |
| underline | u | Bool | false | Underline |
| strikethrough | line-through, delete-line, del | Bool | false | Strikethrough |
| monospace | mono, code | Bool | false | Monospace font (for code/log) |
| letter-spacing | letterspacing, spacing | Float | 0 | Letter spacing (em units) |
| line-height | lineheight, row-height | Float | 0 | Line height multiplier (1.5 = +50%) |
| margin-top | spacing-top, top-margin | Int | 0 | Top margin (dp) |
| margin-bottom | spacing-bottom, bottom-margin | Int | 0 | Bottom margin (dp) |
| alpha | opacity | Float | -1 | Opacity 0.0-1.0 or 0-255 |
| foreground | color | String | -1 | Text color (e.g. #FF0000) |
| bg | background, bgcolor | String | -1 | Background color |
| size | - | Int | -1 | Font size (sp) |
| break | - | Bool | false | Line break after this row |
| line | divider, separator | Bool | false | Draw a horizontal divider before this row |
| align | - | String | normal | normal/center/opposite |
| link | href | String | "" | URL to open on click |
| activity | a, intent | String | "" | Intent to open on click |
| photo | photo-path | String | "" | Large image (own line, separate from text) |
| photo-real-size | photo-original-size | Bool | false | Show image at real size |
| photo-gif-num | gif-num | Int | 0 | >0: image is animated (photo_1.png...) |
| photo-gif-time | gif-time | Int | 300 | Time per frame (ms) |
| photo-gif-autoplay | gif-autoplay | Bool | true | Auto-play the GIF |
| photo-gif-loop | photo-gif-loop-count, gif-loop, gif-loop-count | Int | 0 | Loop count (0=infinite) |
| icon | icon-path | String | "" | new INLINE small icon (same line, different from photo) |
| icon-position | icon-pos | String | before | before / after the text |
| icon-size | - | Int | 0 | Icon size (dp) |
| script | run | String | "" | shell Script to run when the row is clicked |
| toggle | toggle-type | String | "" | checkbox/switch = show a small toggle next to the row |
| get | getstate | Bool|Shell | false | Toggle initial state. A shell returning exactly "1" = checked (queued into pending states - see section 20) |
| set | setstate | String | "" | shell Script run when the user toggles (receives $state = "1"/"0") |
| support | visible | Bool|Shell | true | Hide/show the row |
12.2. Demo
[[text]]
title = "Device info"
[[text.rows]]
text = "Device info"
bold = true
[[text.rows]]
line = true
[[text.rows]]
text = "Model: Pixel 7"
[[text.rows]]
text = "Android: 14"
[[text.rows]]
text = "ro.build.fingerprint=google/raven/..."
monospace = true
[[text.rows]]
line = true
[[text.rows]]
text = "Updated 2024-08-26"
align = "center"
italic = true
[[text.rows]]
line = true
[[text.rows]]
text = "Show notifications"
toggle = "switch"
get = "settings get global heads_up_notifications_enabled"
set = "settings put global heads_up_notifications_enabled $state"
sh (alias text-sh) of a row is NOT queued into the pending-state system - it is left to the UI layer and evaluated when the row is rendered. get with a shell value IS queued into pendingRowCheckedStates and batched at the end - like switch/picker.13. [[editor]] - Open file in the text editor
[[editor]] lets the user open a file in the built-in text editor (TextEditorActivity) to view or edit it. If the file does not exist, the editor creates it when the user saves.
13.1. Editor fields
| Field | Alias | Type | Default | Description |
|---|---|---|---|---|
| file | path | String | "" | required Path of the file to open |
| wrap | - | Bool | true | Enable line wrapping |
| placeholder | - | String | null | Hint when file is empty |
| readonly | - | Bool|Shell | false | Read-only. Accepts shell too! |
| need-input | - | Bool | false | Whether the run script uses read |
| value | - | String | "" | Initial content (only when file does not exist) |
| value-sh | - | String | "" | shell Script that produces initial content (higher priority than value) |
| + ClickableNode fields (icon, lock, min-sdk...) and NodeInfoBase (title, desc...) | ||||
13.2. Demo
[[editor]]
title = "Edit build.prop"
desc = "/system/build.prop"
file = "/system/build.prop"
readonly = "test -w /system/build.prop || echo 1"
[[editor]]
title = "Create new script"
desc = "/sdcard/myscript.sh"
file = "/sdcard/myscript.sh"
value = "#!/system/bin/sh\necho hello"
value is only written when the file does not exist. If the file already exists, value/value-sh are ignored - the existing file content is preserved.14. [[download]] - Download a file via HTTP
[[download]] is a new node type that displays download progress directly in the item (no separate dialog). When download completes, it runs the script with the env var $state = path of the downloaded file (cached, random name). The URL can be static (url) and/or dynamic (url-sh).
14.1. Download fields
| Field | Alias | Type | Description |
|---|---|---|---|
| url | - | String | Static URL (http/https) to download. Required if url-sh is not set |
| url-sh | - | String | shell Script that returns the URL to download. Runs once, the first time the item is tapped - the result is cached into url for the rest of that page visit (pause/resume/retry reuse the cached value, the script is not re-run). Required if url is not set; if both are set, the result of url-sh overwrites url on that first tap |
| script | set, setstate | String | Script run after download. Receives $state = path of downloaded file |
| lock | lock-state | String | Static lock: true/1 or the "1|message" format |
| lock-sh | - | String | shell Script to check lock dynamically (returns "1" = locked) |
| rows | - | Array | Rich-text rows shown below the item - see section 12 |
| + all RunnableNode fields: confirm, warn, reload, auto-finish... | |||
14.2. Demo
[[download]]
title = "Download update"
url = "https://example.com/update.zip"
script = "unzip -o $state -d /sdcard/update && echo Update installed"
15. [[resource]] - Extract assets
[[resource]] is an invisible node (it returns null after initialization). It only extracts assets from the APK to storage (typically /data/data/<pkg>/files/... or cache). This is how to ship script files, images, etc. from the APK to outside so shell can call them.
You can also put resource-file/resource-dir fields directly inside [[page]]/[[action]]/[[switch]]/[[picker]]/[[text]] - no need to declare a separate [[resource]] entry. (Not available on [[group]].)
15.1. Fields
| Field | Alias | Type | Description |
|---|---|---|---|
| resource-file | - | String | Name of a single asset file to extract |
| resource-dir | - | String | Name of an asset directory to extract entirely |
| resources | - | Array | List of more complex resources - each entry is a table with file and/or dir |
[[resource]]
resource-file = "busybox"
[[resource]]
resource-dir = "scripts"
# Or inline on the node that needs it - no separate [[resource]] entry required:
[[action]]
title = "Run bundled script"
resource-file = "run.sh"
script = "sh /data/data/com.tool.tree/files/run.sh"
resource-* fields, support = false skips the whole node - its resources are not extracted either.17. Dependencies (depend-*)
This is the largest feature of [[action.params]]: a param can be hidden/shown (or switched to readonly) based on the value of one (or more) other params in the same action. This is how to build complex dialogs that are still easy to manage - the UI auto-hides irrelevant fields when the user picks a different mode.
17.1. depend-* fields (only for [[action.params]])
| Field | Type | Default | Description |
|---|---|---|---|
| depend-on | String | null | Name(s) of parent param(s), separated by |. E.g. "mode|cam". Alias: depend |
| depend-value | String | null | Required matching value for each parent. Parents separated by |; within one parent: accepted values OR-separated by comma ,. E.g. "a|b,c" |
| depend-mode | String | "show" | "show": show when matched (default). "hide": hide when matched. Can be declared per-parent, separated by |: "show|hide" |
| depend-logic | String | "and" | How to combine multiple parents: and / priority (= or LTR) / priority-rtl (= or RTL) / xor / nand. Alias: depend-priority |
| depend-default | String | "show" | Default value when NO condition matches: "show" or "hide" |
| depend-initial | String | "auto" | Initial state before any evaluation: "auto" / "show" / "hide". Alias: depend-initial-state |
| depend-negate | Bool | false | Invert ALL conditions (NOT logic) |
| depend-threshold | Int | -1 | Only for and: % of conditions that must match (0-100). E.g. 67 = at least 2/3 |
| depend-include-hidden | Bool | true | true: hidden param still included in result. false: skip hidden param |
| depend-cascade | Bool | true | true: parent hidden => child hidden too. false: only visible parents are used |
| depend-onchange | String | null | Shell callback name run when this param's hide/show state changes. Aliases: depend-on-change, depend-callback |
| depend-readonly | Bool | false | new true: don't hide - just dim and lock interaction |
| depend-sort | Bool | false | new true: move locked params to the bottom (only effective when depend-readonly=true) |
17.2. Demo - simple dependency
[[action]]
title = "Backup"
script = """
if [ "$mode" = "file" ]; then
cp "$src_file" /sdcard/backup/
else
cp -r "$dst_folder" /sdcard/backup/
fi
"""
[[action.params]]
name = "mode"
title = "Backup mode"
type = "spinner"
value = "file"
[[action.params.options]]
title = "Single file"
value = "file"
[[action.params.options]]
title = "Whole folder"
value = "folder"
[[action.params]]
name = "src_file"
title = "Source file"
type = "file"
depend-on = "mode"
depend-value = "file"
[[action.params]]
name = "dst_folder"
title = "Destination folder"
type = "folder"
depend-on = "mode"
depend-value = "folder"
depend-sort = true only works when depend-readonly = true. If you declare depend-sort = true without depend-readonly, the parser forces it to false - because sort only makes sense for items "locked in place" (still visible, just dimmed), not for fully hidden items (View.GONE has no slot to "move down").17.3. depend-logic reference
| Logic | Meaning | Example |
|---|---|---|
and (default) | ALL conditions must match | depend-on="a|b" => both a and b must match depend-value |
priority | left-to-right, first matching condition wins | If a matches => result follows a's mode; if a doesn't match, check b... |
priority-rtl | right-to-left, opposite of priority | If b matches before a |
xor | EXACTLY ONE condition must match | a matches OR b matches, not both |
nand | negation of and | NOT all matching => true |
17.4. depend-default and depend-initial
By default, when no condition matches, the param is shown. To change the default to hidden:
depend-initial = "auto" (default) auto-determines based on depend-default. Use "show"/"hide" when you want to avoid "flicker" when the dialog first opens - the UI will pin to that state until evaluation completes.18. Shell-script fields - overview
In Tool-Tree, many fields accept either a static value (string/bool) or a dynamic shell script. The parser runs the script and uses its output as the value. Here is a summary of all shell-style fields:
| Field | Applies to | Description |
|---|---|---|
| title-sh | Node, param, option | Produce title dynamically |
| desc-sh | Node, param | Produce desc dynamically |
| summary-sh | Node | Produce summary dynamically |
| warn-sh / warning-sh | RunnableNode | Produce warning dynamically |
| label-sh | ActionParamInfo | Produce label dynamically |
| placeholder-sh | ActionParamInfo | Produce placeholder dynamically |
| desc-on-sh | ActionParamInfo (type=bool) | Produce desc-on dynamically |
| value-sh | ActionParamInfo, EditorNode | Fetch current value |
| options-sh / option-sh / options-su | PickerNode, ActionParamInfo, PageMenuOption | Produce options list dynamically |
| get / getstate | SwitchNode, PickerNode, PageMenuOption (checkbox/spinner), TextRow (toggle) | Read current state (batched via pending states at parse time) |
| set / setstate / script | ActionNode, SwitchNode, PickerNode, DownloadNode, PageMenuOption, TextRow (toggle) | Set new state on user interaction |
| lock / lock-state | ClickableNode, PageNode, PageMenuOption | Check lock state (static, or "state|message" format) |
| lock-sh | ClickableNode (page, action, switch, picker, download, editor) | Check lock state dynamically (returns "1" = locked) |
| url-sh | DownloadNode | Produce download URL dynamically - runs once on first tap, cached into url for the rest of that page visit |
| support / visible | All nodes, row, param | Hide/show (accepts shell too) |
19. resolveBoolOrShell
The resolveBoolOrShell() function parses fields that can take either a static boolean or a shell command. If the string evaluates to "true" or "1", it resolves to true. For non-boolean strings, it executes the script immediately via the root shell during parsing; if the command output equals "1", it returns true, otherwise false.
20. Pending states
To maximize performance when parsing large configuration files, the parser does not run every dynamic shell evaluation synchronously. Five queues collect the deferred work while parsing:
| Queue | Collected from | Result applied to |
|---|---|---|
pendingSwitchStates | switch get | checked = true when output is "1"/"true" (and not "error") |
pendingPickerStates | picker get | current value |
pendingRowCheckedStates | row get (toggle) | row checked = (output trimmed == "1") |
pendingRowVisibleStates | row support (non-boolean value) | row removed from its list when output != "1" |
pendingDynamicStrings | title-sh/desc-sh/summary-sh of nodes, warn-sh of runnable nodes, title-sh of picker/param options | replaces the static string |
After the whole document is parsed, resolvePendingStates() submits ALL collected scripts in a single batch via ScriptEnvironmen.executeMultipleResultRoot() - one shell round-trip instead of N - and then distributes the results to each node before the page is displayed.
21. process = true
Setting process = true on a [[page]] instructs the rendering engine to build and render child nodes progressively on the UI as they are parsed, accompanied by a linear progress indicator, rather than holding display until the entire tree has loaded. Note that a [[group]] is emitted to the UI only after ALL of its children have been collected (group + children appear together), while items outside any group are emitted one by one as soon as they are parsed.
22. Page lifecycle
Sub-pages trigger lifecycle callbacks during initialization and reading. before-load executes before parsing begins, followed by after-load upon parsing completion. Dependent on the parse status, load-ok or load-fail shell scripts execute accordingly.
23. Script output control sequences
While a script (from [[action]], [[switch]], [[download]] ...) is running, its log dialog is not just a plain text viewer. If a running script echos a line matching one of the special tags below, the log dialog intercepts that line (it is not printed as normal output) and performs a UI action instead. This lets a shell script drive dialogs, prompts, progress bars, and even control the app process itself, without leaving the log screen.
tagname:[content], printed on its own line via echo. They only work while the log dialog is open and reading the script's live output.23.1. exit:[kill] / exit:[restart]
Terminates the app process from inside a running script. exit:[kill] simply kills the app process; exit:[restart] relaunches the app first and then kills the old process, giving the effect of a full app restart.
[[action]]
title = "Apply and restart app"
confirm = true
warn = "The app will restart to apply changes"
script = """
setprop persist.sys.my_tweak 1
echo "exit:[restart]"
"""
exit:[...] line is never processed - the process is torn down as soon as the tag is detected.23.2. choose:[value1|Label1,value2|Label2,...]
Pauses the script and renders a row of buttons directly in the log dialog. Each option is value|Label (the |Label part is optional - if omitted, the value itself is used as the label). When the user taps one, its value is written back to the script's standard input, and the script resumes.
[[action]]
title = "Set governor"
script = """
echo "choose:[performance|Performance,powersave|Power saving,schedutil|Balanced]"
read governor
echo "userspace" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null
for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo "$governor" > "$cpu"
done
echo "Governor set to: $governor"
"""
23.3. pick:[values] / pickv:[values] / pickh:[values]
Same idea as choose:[...] (comma-separated value|Label list, sent back via stdin on tap), but rendered as tappable links inline in the log text rather than as separate buttons. pickv:[...] (or plain pick:[...]) stacks the choices vertically; pickh:[...] lays them out horizontally.
[[action]]
title = "Choose log level"
script = """
echo "Select a verbosity level:"
echo "pickh:[1|Low,2|Medium,3|High]"
read level
echo "Verbosity set to level $level"
"""
23.4. input:[prompt]
Shows a text input field in the log dialog with prompt as its hint. Whatever the user types and submits is written back to the script's standard input, letting the script keep going with free-form text instead of a fixed list of choices.
[[action]]
title = "Rename backup"
script = """
echo "input:[Enter a name for this backup]"
read name
mv /sdcard/backup/last.zip "/sdcard/backup/${name}.zip"
echo "Saved as ${name}.zip"
"""
23.5. progress:[current/total]
Drives the progress bar shown at the top of the log dialog. Echo this repeatedly while a long-running task advances. current = -1 switches the bar to indeterminate (spinning) mode; current >= total hides the bar (task finished).
[[action]]
title = "Copy large folder"
script = """
echo "progress:[-1/100]"
total=$(ls /sdcard/source | wc -l)
i=0
for f in /sdcard/source/*; do
cp "$f" /sdcard/target/
i=$((i+1))
echo "progress:[$i/$total]"
done
echo "progress:[$total/$total]"
echo "Done: $i files copied"
"""
23.6. am:[...] (send an Android Intent)
Sends an Android Intent directly from a shell script, without needing a separate am start binary call wired up elsewhere. Supported sub-commands are start, startservice, foregroundservice, and broadcast, using the same -a/-d/-n flags as the standard Android am command line tool, plus typed extras.
| Extra flag | Type |
|---|---|
--es key value | String |
--ei key value | Int |
--ez key value | Boolean |
--el key value | Long |
--ef key value | Float |
--ed key value | Double |
--eu key value | Uri |
--esa key v1 v2 | String[] |
--eia key v1 v2 | Int[] |
[[action]]
title = "Open developer options"
script = """
echo "am:[start -a android.settings.APPLICATION_DEVELOPMENT_SETTINGS]"
"""
[[action]]
title = "Broadcast a custom event"
script = """
echo "am:[broadcast -a com.example.MY_ACTION --es status ok --ei code 200]"
"""
am:[help] from any script to print the full command/extras syntax straight into the log dialog - handy for testing without leaving the app.24. Full example
A representative TOML configuration showcasing groups, actions, parameters, switches, and rich text rows:
# Top-level item (declared before the first [[group]]) - shown without a group header
[[text]]
title = "NOTICE"
[[text.rows]]
text = "Every entry below belongs to the nearest [[group]] above it"
italic = true
[[group]]
title = "System Performance"
[[switch]]
title = "Performance Mode"
desc = "Enable performance governor"
get = "getprop sys.perf.mode"
set = "setprop sys.perf.mode $state"
lock-sh = "[ -f /data/adb/.perf-ready ] && echo 1"
[[action]]
title = "Set CPU Frequency"
script = "echo $freq > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
reload = "perf-mode"
[[action.params]]
name = "freq"
title = "Frequency (kHz)"
type = "spinner"
[[action.params.options]]
title = "Mode 1"
value = "1800000"
[[action.params.options]]
title = "Mode 2"
value = "2200000"
[[action.rows]]
text = "Applies to CPU0 only"
italic = true
[[group]]
title = "Maintenance"
[[action]]
title = "Clear cache"
confirm = true
warn = "Cache will be wiped!"
script = "sync; echo 3 > /proc/sys/vm/drop_caches"
auto-off = true
# Page menu (3-dot) and FAB - collected wherever they appear
[[menu]]
handler = "echo Menu: $key"
[[menu.items]]
title = "Refresh"
type = "refresh"
[[menu.items]]
title = "Performance Mode"
type = "checkbox"
get = "getprop sys.perf.mode"
script = "setprop sys.perf.mode $state"
[[fab]]
[[fab.items]]
title = "Flash zip"
type = "file"
suffix = "zip"
script = "sh $state"
25. Tips & pitfalls
- Always use double brackets
[[node]]across all declarations to prevent TOML table array parser exceptions. - Groups are flat - never use dotted
[[group.action]]nesting (those children are silently ignored). Declare children flat, right after their[[group]]. [[toml]]is a reserved marker for inline-TOML detection (config-sh) - do not use it as a node table name.- Use selective refresh via
reload = "id1,id2"instead of reloading the entire page after action execution.