> ## Documentation Index
> Fetch the complete documentation index at: https://docs.atonom.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Write Lua

> Write transforms, validate inputs, and return JSON-compatible results.

Stored Lua tools expose one entry point: `transform(context)`. The input schema defines the keys a platform agent supplies; the function returns a JSON-compatible value.

## Validate the input contract

```lua theme={null}
function transform(context)
  if type(context.email) ~= "string" or context.email == "" then
    error("email is required")
  end
  return { email = string.lower(context.email) }
end
```

Use `error(...)` for a failed execution. Returning `{ ok = false, error = "..." }` is a normal tool result and does not by itself make the CLI exit with code 2. Choose the behavior that your caller expects.

Lua treats `0` and `""` as truthy. The expression `value or default` substitutes for both `nil` and `false`; use an explicit `nil` check when `false` is meaningful.

## JSON values

```lua theme={null}
function transform(context)
  return {
    name = "Ada",
    active = false,
    tags = atonom.json.array(),
    manager = atonom.json.null
  }
end
```

This produces an object with `tags: []` and `manager: null`.

* Sequential tables encode as arrays; string-keyed tables encode as objects.
* An empty `{}` encodes as an object, not an array.
* `atonom.json.array(...)` explicitly creates an array, including an empty one.
* `atonom.json.null` preserves a JSON null inside a table.
* Assigning `nil` removes a table entry, so the key is omitted.

Return a Lua value directly. Do not encode your entire result to text unless the caller wants a JSON **string** rather than an object.

## Encode and decode JSON text

```lua theme={null}
local value, err = atonom.json.decode('{"active":true}')
if err then
  error(err)
end
local text, encode_err = atonom.json.encode(value)
if encode_err then
  error(encode_err)
end
```

Decoded JSON null uses `atonom.json.null`. Validate a decoded value's shape before indexing it. These helpers are part of the Atonom sandbox, not standard Lua libraries.

## Call a host capability

```lua theme={null}
local result, err = atonom.toolcall("web_search", { query = "acme" })
if err then
  return { ok = false, error = err }
end
return { ok = true, result = result }
```

`atonom_toolcall(...)` is an alias. Capability names use letters, digits, and underscores (`[A-Za-z0-9_]+`); arguments must be a table or omitted. The return convention is `(value, nil)` on success and `(nil, error_string)` on failure. Use host error strings directly.

The sandbox emits a trap; it does not look up tools or make network requests. The host determines which capabilities actually exist and which calls are allowed. `web_search` here is an example name, not a guarantee that your platform agent has such a tool.

See [Test & mock tool calls](/atonom-script/cli/testing) for runnable examples.

## Sandbox limits

The CLI's authoring contract specifies LuaJIT with the JIT disabled, with the base, table, string, math, and bit libraries. Do not depend on `io`, `os`, `package`, `ffi`, or `coroutine`, or assume that every base-library operation is available. There is no filesystem, clock, or direct network access.

The runtime is configured for **32 MiB memory and 2 seconds CPU per execution slice**. Host I/O occurs outside that slice. Stored script bodies have a **64 KiB authoring limit**. Keep loops bounded and outputs small; increasing the CLI's HTTP timeout does not raise Lua CPU or memory limits.

Prefer deterministic transforms and explicit inputs. Keep direct transformations side-effect free; host capabilities can perform external actions depending on the host's implementation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.