Validation rules
What the platform rejects before a smart app runs.
Smart-app code is checked when it is registered or generated. These rules are enforced server-side; the runtime enforces the same limits again.
Size
Source must be at most 131,072 characters (128 KiB).
Timer rules
Global timer APIs the smart-app isolate does not expose (see apps/edge-runtime/src/assets/isolateHelpers.js) — calls would throw at runtime. The prompts steer to runIn / runOnce / runDaily / schedule / unschedule; smaller models still slip back to the JS-standard names occasionally, so we enforce server-side.
match says how the name is detected: call only as name(, identifier as any bare use, method only as .name(.
| Banned name | Match |
|---|---|
setTimeout | call |
setInterval | call |
clearTimeout | call |
clearInterval | call |
User restricted rules
Isolate APIs excluded from the end-user AI-automation surface (v1 scope: entity triggers/actions, schedules, presence/mode conditions, push notifications). These EXIST in the isolate — the ban is a product decision, not a missing binding — so match bare identifiers to also catch aliasing.
match says how the name is detected: call only as name(, identifier as any bare use, method only as .name(.
| Banned name | Match |
|---|---|
sendSms | identifier |
sendEmail | identifier |
httpRequest | identifier |
runSmartApp | identifier |
pauseSmartApp | identifier |
resumeSmartApp | identifier |
listSmartAppInstances | identifier |
getChildApps | identifier |
getParent | identifier |
getChildAppById | identifier |
sendToHostSync | identifier |
sendToHostAsync | identifier |
Local time rules
Local-time Date instance methods. The isolate's new Date() runs in the edge-runtime PROCESS timezone (usually UTC), not the home's — so any handler-internal wall-clock logic built on these evaluates in the wrong zone (e.g. "only between 10pm and 6am" firing on UTC hours). The correct idiom is formatDateParts(new Date(), getHomeTimeZone()). Epoch math (Date.now(), .getTime()) and the getUTC* family are TZ-independent and stay allowed.
match says how the name is detected: call only as name(, identifier as any bare use, method only as .name(.
| Banned name | Match |
|---|---|
getHours | method |
getMinutes | method |
getDay | method |
getDate | method |
getMonth | method |
getFullYear | method |
getTimezoneOffset | method |
toLocaleString | method |
toLocaleTimeString | method |
toLocaleDateString | method |
User automation rules
Timer rules + the user-surface capability ban + the local-time ban, for user-generated code. (The admin chat surface stays timer-only — it emits engineer-facing suggestions, not fail-closed installs.)
match says how the name is detected: call only as name(, identifier as any bare use, method only as .name(.
| Banned name | Match |
|---|---|
setTimeout | call |
setInterval | call |
clearTimeout | call |
clearInterval | call |
sendSms | identifier |
sendEmail | identifier |
httpRequest | identifier |
runSmartApp | identifier |
pauseSmartApp | identifier |
resumeSmartApp | identifier |
listSmartAppInstances | identifier |
getChildApps | identifier |
getParent | identifier |
getChildAppById | identifier |
sendToHostSync | identifier |
sendToHostAsync | identifier |
getHours | method |
getMinutes | method |
getDay | method |
getDate | method |
getMonth | method |
getFullYear | method |
getTimezoneOffset | method |
toLocaleString | method |
toLocaleTimeString | method |
toLocaleDateString | method |
Domain state vocabulary
States the validator accepts in subscription filters per domain.
| Domain | States |
|---|---|
light | on, off |
switch | on, off |
fan | on, off |
siren | on, off |
remote | on, off |
input_boolean | on, off |
binary_sensor | on, off |
lock | unlocked, locked, unlocking, locking |
cover | open, closed, opening, closing |
valve | open, closed, opening, closing |
climate | off, cool, heat, heat_cool, fan_only, dry |
media_player | playing, paused, stopped, buffering |
camera | idle, recording, streaming |
presence | present, not_present |
sun | ABOVE_HORIZON, BELOW_HORIZON |
Non-entity input types
Input types the validator recognises as non-entity: /type\s*:\s*['"](?:time\|date\|text\|string\|email\|number\|enum\|array\|boolean\|password\|thermostatSchedule)['"]/