Built-in Modules
require serves two kinds of module. Installed libraries are plugins. Built-in modules are provided by the runtime directly, under the internal. prefix, because they need to be the host itself: a log line has to carry the trigger and script it came from, a clock has to be the host’s clock. A plugin cannot claim a namespace starting with internal..
internal.logging
Section titled “internal.logging”local log = require("internal.logging")log.debug(message[, fields])log.info(message[, fields])log.warn(message[, fields])log.error(message[, fields])fields is a table stored as JSON on the event, so log.error("save failed", { uri = uri, err = tostring(err) }) is queryable rather than a stringified blob. info, warn and error are recorded as script.log events in the event log, carrying the trigger id and caller; debug writes only to the process log. In a job script, info/warn/error also write to that job’s own log.
internal.time
Section titled “internal.time”local time = require("internal.time")time.now() -- unix milliseconds, integertime.to_iso8601(ms) -- "2026-09-13T15:04:05.000Z", raises on an out-of-range timestamptime.from_iso8601(string) -- unix milliseconds, or nil on an unparseable stringtime.to_iso8601(time.now()) is the current UTC timestamp for a createdAt field.
internal.tids
Section titled “internal.tids”local tids = require("internal.tids")tids.create() -- a fresh TID for nowtids.to_tid(ms) -- TID for a unix-millisecond timestamptids.from_tid(tid) -- unix milliseconds, raises on an invalid TIDA TID is atproto’s 13-character sortable record key. tids.create() is the rkey to use when a script needs to name a record before writing it.
internal.json
Section titled “internal.json”local json = require("internal.json")json.encode(value) -- Lua value -> JSON stringjson.decode(string) -- JSON string -> Lua valuejson.to_array(table) -- marks a table as a JSON array, so an empty one encodes as [] rather than {}Encoding rules and examples: JSON.
Next steps
Section titled “Next steps”- Script Contract:
handle(input, ctx)and wherectxcomes from - Libraries: the
happyview.*modules, reached the same way viarequire

