# `Lemma`
[🔗](https://github.com/lemma/lemma/blob/main/lib/lemma.ex#L1)

Lemma rules engine for Elixir.

Wraps the Lemma engine (Rust) via NIFs. Create an engine, load sources,
run evaluations, and show specs.

## Example

    {:ok, engine} = Lemma.new()
    :ok = Lemma.load(engine, "spec foo\ndata x: 1\nrule y: x + 1")
    {:ok, response} = Lemma.run(engine, %{spec: "foo"}, %{data: %{}})
    # response is a map from decoded JSON

## Engine lifecycle

Each engine is an opaque resource. Do not share the same engine ref across
processes unless you serialize access (e.g. via a GenServer).

# `engine`

```elixir
@type engine() :: reference()
```

# `limits_map`

```elixir
@type limits_map() :: %{required(String.t()) =&gt; pos_integer()} | nil
```

# `repository`

```elixir
@type repository() :: String.t() | nil
```

# `spec_name`

```elixir
@type spec_name() :: String.t()
```

# `format`

```elixir
@spec format(String.t()) :: {:ok, String.t()} | {:error, term()}
```

Formats Lemma source code. Does not require an engine instance.

# `limits`

```elixir
@spec limits(engine()) :: {:ok, map()} | {:error, term()}
```

Returns the engine's configured resource limits.

# `list`

```elixir
@spec list(engine()) :: {:ok, [map()]} | {:error, term()}
```

Lists loaded specs grouped by repository (metadata only).

# `load`

```elixir
@spec load(engine(), String.t()) :: :ok | {:error, [map()]}
@spec load(engine(), map() | [{String.t(), String.t()}]) :: :ok | {:error, [map()]}
```

Loads Lemma source(s).

- binary → one volatile workspace source
- `[{label, code}, ...]` → labeled sources in caller list order
- map → labeled sources in lexicographic label order (BEAM maps have no insertion order)

# `new`

```elixir
@spec new(limits_map()) :: {:ok, engine()} | {:error, term()}
```

Creates a new engine. Optionally pass a map of resource limits; omitted keys use defaults.

# `quality`

```elixir
@spec quality(engine()) :: {:ok, [map()]} | {:error, term()}
```

Structural quality recommendations across loaded specs. Advisory only.

# `remove`

```elixir
@spec remove(engine(), repository(), spec_name(), String.t() | nil) ::
  :ok | {:error, term()}
```

Removes a temporal spec slice.

Positional args: `repository`, `spec`, `effective`.

# `run`

```elixir
@spec run(engine(), map(), map()) :: {:ok, map()} | {:error, term()}
```

Runs a spec.

`target` is `%{repo: repository | nil, spec: name, effective: datetime | nil}`.
`options` is `%{data: map, rules: [String.t()] | nil, explain: boolean}` (defaults apply when omitted).

Each rule result may include `missing_data` (unbound input keys as strings). Types,
prefilled literals, and suggestions are on `show/4` only — not on the evaluate response.

# `show`

```elixir
@spec show(engine(), repository(), spec_name(), String.t() | nil) ::
  {:ok, map()} | {:error, term()}
```

Returns spec interface and temporal window at `effective`.

Positional args: `repository`, `spec`, `effective`.

# `source`

```elixir
@spec source(engine(), repository(), spec_name() | nil, String.t() | nil) ::
  {:ok, String.t()} | {:error, term()}
```

Returns formatted canonical Lemma source.

Omit `spec` for whole-repository text. When `spec` is set, `effective` selects the slice.

# `update`

```elixir
@spec update(
  engine(),
  repository(),
  spec_name(),
  String.t() | nil,
  String.t(),
  String.t() | nil
) :: :ok | {:error, [map()]}
```

Replaces a temporal spec slice with new source (atomic remove + load).

`attribute` is the source label (path or `@owner/repo`). Omit (`nil`) for a volatile source.

---

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