# Isabelle Elixir
Elixir clients for the [Isabelle](https://isabelle.in.tum.de/) server.
The library speaks Isabelle's server protocol directly. See Chapter 4 in the [Isabelle system manual](https://isabelle.in.tum.de/doc/system.pdf) for the specification.
## Clients
`IsabelleClientMini` is the low-level building block. It is stateless, exposes
the TCP socket, and gives you explicit `command/3`, `async_command/3`, and
`await_task/3` helpers.
`IsabelleClient` is the default client for scripts and notebooks. It keeps the
socket and current `session_id` in a struct, and awaits asynchronous Isabelle
tasks for the common session workflow.
`IsabelleClientFull` is a `GenServer` wrapper. It owns the socket, so callers
may safely share it across processes. Calls are serialized by design.
## Tutorial Livebooks
The notebooks in `livebook_examples/` are intended to be read and run in this
order:
1. `IsabelleClientMini.livemd` introduces the wire-level building blocks and
explicit task handling.
2. `IsabelleClient.livemd` shows the default stateful client for ordinary use.
3. `IsabelleClientFull.livemd` shows the process-owning client and why it is
the right choice when multiple Elixir processes share one Isabelle
connection.
Together they serve as the tutorial for the library. They start local Isabelle
servers, run smoke tests, build and start a `HOL` session, check theories,
purge, stop, and clean up. The "Full" notebook additionally demonstrates
concurrency-safe access.
## Example
Make sure Isabelle is available on `PATH`:
```sh
export PATH=/path/to/Isabelle2025-2/bin:$PATH
```
Then:
```elixir
{:ok, [server]} = IsabelleClientMini.new_server("elixir", 0)
{:ok, client} =
IsabelleClient.connect(server["password"],
host: server["host"],
port: server["port"]
)
{:ok, client, _task} = IsabelleClient.start_session(client, %{"session" => "HOL"})
File.write!("/tmp/Example.thy", """
theory Example imports Main
begin
theorem "x = x"
sledgehammer by simp
proposition "x = y"
nitpick oops
end
""")
{:ok, task} =
IsabelleClient.use_theories(client, %{
"theories" => ["Example"],
"master_dir" => "/tmp"
})
IO.puts(IsabelleClientMini.extract_results(task))
{:ok, _client, _task} = IsabelleClient.stop_session(client)
```