General
This page covers common values and services available to Scripted Decorations. TaskManSync embeds Lua 5.5.1 with the base, math, string, table, and utf8 libraries. It does not provide ordinary io, os, debug, or coroutine libraries, or load, dofile, and loadfile. Use the typed time, fs, and process APIs instead of os.date, io.open, or os.execute. Pure-Lua module loading is installed separately as described below.
| API | Purpose |
|---|---|
log.debug(message) | Debug diagnostic |
log.info(message) | Informational diagnostic |
log.warning(message) | Warning diagnostic |
log.error(message) | Error diagnostic |
time.now() | Current system date/time |
time.dateTime{...} | Construct a date/time value |
time.duration.milliseconds/seconds/minutes/hours(value) | Construct signed durations |
time.instant.milliseconds(value) | Reconstruct an instant from signed milliseconds |
time.instant.toMilliseconds(instant) | Convert an instant for persistence |
time.duration.toMilliseconds(duration) | Convert a duration for persistence |
time.localDateTime(instant) | Convert an instant to local calendar fields |
json.encode(value) | Encode structured data as JSON |
json.decode(text) | Decode JSON |
json.null | Preserve explicit JSON null |
json.object() | Construct an explicitly empty JSON object |
requestUpdate() | Request one coalesced Decoration update |
scheduler.at(deadline, "callbackName") | Schedule one callback |
require(name) | Load a user-owned pure-Lua module |
package.path | Configure pure-Lua module search paths |
Structured values are bounded. The common limits are 32 nested levels, 4,096 total values, 256 KiB strings, and 1 KiB object keys. JSON input and output are each limited to 256 KiB.
The bounds apply to copied API data, not all Lua variables. TaskManSync intentionally imposes no arbitrary per-script Lua-heap quota. Actual allocation failures can still occur, and execution time/instruction budgets can fault runaway callbacks. Native operations, queues, and resources retain their own limits. This is trusted local-user scripting, not an untrusted-code sandbox.
Time and Values
time.now() returns a system-clock instant. time.dateTime{ year=2030, month=1, day=1, hour=12, minute=30, second=0 } constructs a local-system instant. Instants and durations are semantic values, not ordinary millisecond numbers: add a duration to an instant, subtract two instants to obtain a duration, and compare values of the same kind. Duration arithmetic also supports addition/subtraction and numeric scaling.
Calendar constructors require integer year, month, and day; optional hour, minute, second, and millisecond default to zero. Invalid dates/times raise a Lua error. Duration constructors take signed integers in their named units; for half a second, use time.duration.milliseconds(500), not time.duration.seconds(0.5). Arithmetic overflow and division by zero are errors rather than silently wrapped values.
local deadline = time.now() + time.duration.minutes(5)
local remaining = deadline - time.now()
if remaining > time.duration.seconds(0) then
local seconds = time.duration.toMilliseconds(remaining) / 1000
decoration.text = string.format("Remaining: %.0f s", seconds)
end
storage.set("deadline", time.instant.toMilliseconds(deadline))
local restored = time.instant.milliseconds(storage.get("deadline"))Store signed milliseconds, then reconstruct the corresponding instant or duration. Storage/JSON do not accept semantic time values themselves. time.instant.toMilliseconds is an absolute instant, not local calendar fields. For display, use time.localDateTime(instant): it returns year, month, day, hour, minute, second, millisecond, and weekday (Monday 1 through Sunday 7) in the OS-configured timezone. There is no public timezone-management API. Scheduling explains restoring deadlines and effects of clock changes.
Copied structured values can be nil, booleans, signed 64-bit integers, finite numbers, valid UTF-8 strings, contiguous one-based arrays, or string-keyed objects. Sparse/mixed tables, non-integer numeric keys, cycles, invalid UTF-8, NaN/infinity, functions, threads, and arbitrary userdata/handles are rejected. Each API states whether it accepts these values or a more specialized type.
json.encode(value) and json.decode(text) are synchronous computation returning the result or nil, error. The error has operation ("encode" or "decode"), code, message, and sometimes a zero-based UTF-8 byte offset for malformed input. An unmarked empty table encodes as []; use json.object() for {}. Use json.null to keep a null member, because assigning Lua nil removes a table field. Decoded objects keep object shape even after their members are removed. Numeric spelling and arbitrary precision are not preserved.
local payload = { title = "Reminder", detail = json.null, settings = json.object() }
local text, encodeError = json.encode(payload)
if not text then
log.error(encodeError.message)
else
local decoded, decodeError = json.decode(text)
if decodeError then
log.error(decodeError.message)
elseif decoded.detail == json.null then
log.info("Detail was explicitly null")
end
endJSON conversion neither writes storage nor starts a network request. Concepts covers persistence and diagnostics; Desktop combines HTTP with checked JSON decoding.
Pure-Lua Modules
The pure-Lua module system starts with:
./?.lua;./?/init.luaIt does not load native modules. package.loadlib, package.cpath, native searchers, dofile, and loadfile are unavailable.
The package surface is package.loaded, package.preload, package.path, package.searchers, and package.searchpath. require("format.status") substitutes format/status into each ? pattern, then loads text source through the filesystem API. Relative patterns use the imported-source directory or the captured host working directory; see Files and Modules. Set absolute patterns when sharing modules across definitions. Change /home/alex/tms-lua below to your own directory:
package.path = "/home/alex/tms-lua/?.lua;/home/alex/tms-lua/?/init.lua"
local formatter = require("format.status")
function onLoad()
decoration.text = formatter.count(3)
endCreate the corresponding /home/alex/tms-lua/format/status.lua file separately:
local formatter = {}
function formatter.count(value)
return "Count: " .. value
end
return formatterThese are separate files, not one combined script. Modules run in the same Lua state and capabilities as their caller, not in isolated runtimes. package.loaded caches truthy results by exact module name; a module returning no result becomes true. Updating a module file does not replace a cached module automatically: reload the Decoration to start a fresh module state. There is no native loader, module whitelist, package manifest, or TaskManSync library folder. User-provided Lua preload functions and pure-Lua searchers are supported.
package.searchpath(name, path[, sep[, rep]]) only substitutes and normalizes paths and returns the first candidate. Unlike standard Lua filesystem search, it does not check that a file exists. Use require to actually load a module. Missing files, invalid source, or failed module initialization can raise a Lua error; Import/Save compile-only checks do not execute require or validate module contents.