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.
Nodes can be nested (e.g. [[group.action]] is an action inside a group) to build a hierarchical tree.
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; can be nested |
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. Nesting = dotted path
A child node of a group is declared using the dotted path [[group.type]] (or [[group.subgroup.type]] for deeper nesting). Child nodes always belong to the most recently declared group above them in the file.
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.
resolveBoolOrShell does NOT run immediately during page parsing for readonly/support of action or checked of switch - these 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.
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 entire group. Accepts shell too! |
5.2. Demo
5.3. Multi-level nesting
Groups can be nested inside other groups to build deep trees:
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 | shell Shell to check the lock state |
| rows | - | Array | Rich-text rows shown below the page (see section 12) |
6.2. Demo
config-sh returns one of two things: either a .toml file path (ending with .toml), or inline TOML content (whose first or second non-empty line starts with [[group]] or [[group.). The parser auto-detects - see PageConfigSh.looksLikeInlineToml().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 | shell Script to check lock. If it returns "1", the action is locked (not clickable) |
| 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
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). Accepts shell too! |
| 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) |
| 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
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 |
| set | setstate, script | String | required Script to set state. Receives $state = "1"/"0" |
| lock | lock-state | String | shell Script to check lock |
| + all fields of RunnableNode, ClickableNode, NodeInfoBase | |||
9.2. Demo
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, script | 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 | shell Script to check lock |
| + all fields of RunnableNode, ClickableNode, NodeInfoBase | |||
10.2. Demo
[[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
12. [[text.rows]] - Rich text row
This is the most common display component: used in [[text]], [[action]], [[page]], [[download]] and [[group.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 | - | 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, 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 | Int | 0 | Top margin (dp) |
| margin-bottom | spacing-bottom | 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 | 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 |
| checked | checked-sh, check | Bool|Shell | false | Toggle state. Accepts shell too! |
| onchange-sh | on-change-sh, toggle-sh, set-sh | String | "" | shell Script to run when the user toggles (receives $state) |
| support | visible | Bool|Shell | true | Hide/show the row |
12.2. Demo
sh for a row runs IMMEDIATELY during page parse (synchronous, not pending). checked when shell 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
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).
14.1. Download fields
| Field | Alias | Type | Description |
|---|---|---|---|
| url | - | String | required URL (http/https) to download. Only static URLs are supported - no url-sh |
| script | set, setstate | String | Script run after download. Receives $state = path of downloaded file |
| lock | lock-state | String | shell Script to check lock |
| rows | - | Array | Rich-text rows shown below the item - see section 12 |
| + all RunnableNode fields: confirm, warn, reload, auto-finish... | |||
14.2. Demo
url-sh (script generating URL dynamically). The URL must be a constant in the TOML file.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 [[group]]/[[action]]/[[page]]/[[switch]]/[[picker]]/[[text]] - no need to declare a separate [[resource]] entry.
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 |
ExtractAssets.extractResource() and extractResources() check if the file already exists before re-extracting. To avoid re-extracting on every run, use support = "test -f ..." to only extract when needed.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" |
| 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 |
| 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" |
| 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 |
| 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
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, row | 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(spinner) | Read current state (batched via pending states at parse time) |
| set / setstate / script | SwitchNode, PickerNode, ActionNode, DownloadNode, EditorNode, PageMenuOption | Set new state on user interaction |
| lock / lock-state | ClickableNode, PageNode, PageMenuOption | Check lock state |
| 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 shell script in the background; if the command output equals "1", it returns true, otherwise false.
20. Pending states
To maximize performance when parsing large configuration files, dynamic shell evaluations for nodes (such as get scripts for switches or lock checks) are queued into pending state batches rather than executed synchronously one by one. Once reading finishes, all pending states run asynchronously to update node UI values in a single pass.
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.
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. Full example
A representative TOML configuration showcasing groups, actions, parameters, switches, and rich text rows:
[[group]]
title = "System Performance"
[[group.switch]]
title = "Performance Mode"
desc = "Enable performance governor"
get = "getprop sys.perf.mode"
set = "setprop sys.perf.mode $state"
[[group.action]]
title = "Set CPU Frequency"
script = "echo $freq > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
[[group.action.params]]
name = "freq"
title = "Frequency (kHz)"
type = "spinner"
[[group.action.params.options]]
title = "Mode 1"
value = "1800000"
[[group.action.params.options]]
title = "Mode 2"
value = "2200000"
24. Tips & pitfalls
- Always use double brackets
[[node]]across all declarations to prevent TOML table array parser exceptions. - Keep nesting structures under 3 levels deep to maintain responsive UI performance and code clarity.
- Use selective refresh via
reload = "id1,id2"instead of reloading the entire page after action execution.