# `Puck.Sandbox.Eval.Lua`
[🔗](https://github.com/bradleygolden/puck/blob/v0.2.25/lib/puck/sandbox/eval/lua.ex#L1)

Execute Lua code in a sandboxed environment.

Uses tv-labs/lua (Luerl), a pure Erlang Lua implementation. Provides:
- CPU limits via timeout
- Memory limits via process heap limits
- Host callbacks for safe interaction with your application
- Complete crash isolation (pure Erlang, no NIF)

## Usage

    # Simple eval
    {:ok, result} = Puck.Sandbox.Eval.Lua.eval("return 1 + 2")
    # => {:ok, 3}

    # With callbacks
    {:ok, result} = Puck.Sandbox.Eval.Lua.eval("""
      local products = search_products("laptop")
      local cheap = {}
      for _, p in ipairs(products) do
        if p.price < 1000 then table.insert(cheap, p) end
      end
      return cheap
    """, callbacks: %{
      "search_products" => &MyApp.Products.search/1
    })

    # With resource limits
    {:ok, result} = Puck.Sandbox.Eval.Lua.eval(code,
      callbacks: %{...},
      timeout_ms: 5_000,
      max_heap_words: 1_000_000
    )

## Requirements

Requires the `lua` package: `{:lua, "~> 0.4.0"}`

## Options

- `:callbacks` - Map of callback names to functions (e.g., `%{"name" => &Mod.fun/1}`)
- `:timeout_ms` - Execution timeout in ms (default: 5_000)
- `:max_heap_words` - Memory limit in words (default: 1_000_000, ~8MB on 64-bit)

## Safety

Luerl sandboxes by default, blocking:
- `io` module (file I/O)
- `os.execute`, `os.exit`, `os.getenv`, `os.remove`, `os.rename`, `os.tmpname`
- `load`, `loadfile`, `loadstring`, `dofile`, `require`
- `package` module

The only risk is user-provided callbacks.

# `eval`

Evaluates Lua code in a sandboxed environment.

Returns `{:ok, result}` on success or `{:error, reason}` on failure.

## Examples

    {:ok, 3} = Puck.Sandbox.Eval.Lua.eval("return 1 + 2")

    {:ok, result} = Puck.Sandbox.Eval.Lua.eval("""
      local x = 0
      for i = 1, 100 do x = x + i end
      return x
    """)
    # => {:ok, 5050}

    {:error, :timeout} = Puck.Sandbox.Eval.Lua.eval("while true do end", timeout_ms: 100)

# `eval!`

Like `eval/2` but raises `Puck.Sandbox.Eval.Lua.Error` on failure.

## Examples

    3 = Puck.Sandbox.Eval.Lua.eval!("return 1 + 2")

# `schema`

Returns a Zoi schema for the `ExecuteCode` struct.

The schema includes guidance in the `code` field description to help LLMs
generate valid Lua code (e.g., always use `return` to return values).

## Arguments

- `func_spec` - A Zoi schema describing the available callback functions.
  The LLM will see this schema and understand what functions it can call.

## Example

    @func_spec Zoi.object(%{
      name: Zoi.enum(["double", "search"]),
      description: Zoi.string()
    }, unrecognized_keys: :error, coerce: true)

    schema = Zoi.union([
      Puck.Sandbox.Eval.Lua.schema(@func_spec),
      Zoi.struct(Done, %{type: Zoi.literal("done"), message: Zoi.string()}, coerce: true)
    ])

    # Pattern match on the struct:
    case action do
      %Puck.Sandbox.Eval.Lua.ExecuteCode{code: code} ->
        Puck.Sandbox.Eval.eval(:lua, code, callbacks: callbacks)
      %Done{message: msg} ->
        {:ok, msg}
    end

---

*Consult [api-reference.md](api-reference.md) for complete listing*
