diff --git a/INTERACTIVE_QUICKSTART_WIDGET.md b/INTERACTIVE_QUICKSTART_WIDGET.md
index 434cb606..1f05c09c 100644
--- a/INTERACTIVE_QUICKSTART_WIDGET.md
+++ b/INTERACTIVE_QUICKSTART_WIDGET.md
@@ -5,8 +5,8 @@
- Laptop with Ollama
- Laptop with llama.cpp
- Macbook with MLX
-- iOS with LEAP SDK
-- Android with LEAP SDK
+- iOS with llama.cpp
+- Android with llama.cpp
- Cloud with vLLM
- Browser with Transformers.js
diff --git a/README.md b/README.md
index 6629ea3c..0ebf1e58 100644
--- a/README.md
+++ b/README.md
@@ -6,15 +6,14 @@
/>
@@ -367,6 +371,31 @@ python convert_hf_to_gguf.py /path/to/your/model --outfile model.gguf --outtype
Use `--outtype` to specify the quantization level (e.g., `q4_0`, `q4_k_m`, `q5_k_m`, `q6_k`, `q8_0`, `f16`).
+## Building Applications
+
+The guides below cover embedding llama.cpp in your own software — from a mobile app calling the C API to a desktop app driving `llama-server`:
+
+
+
+ Link the XCFramework or NDK build and run LFM GGUFs in-process.
+
+
+ llama-server as a sidecar, or Python / Node.js / .NET bindings.
+
+
+ Multi-turn conversations, sampling parameters, prompt caching.
+
+
+ OpenAI-style tools with native LFM2.5 tool-call parsing.
+
+
+ JSON schema and GBNF grammar constrained generation.
+
+
+ LFM2.5-VL and LFM2.5-Audio on llama.cpp.
+
+
+
## Example Applications
For more comprehensive example applications using llama.cpp with LFM models, check out these repositories:
diff --git a/deployment/on-device/llama-cpp/chat.mdx b/deployment/on-device/llama-cpp/chat.mdx
new file mode 100644
index 00000000..2aad9492
--- /dev/null
+++ b/deployment/on-device/llama-cpp/chat.mdx
@@ -0,0 +1,210 @@
+---
+title: "Chat & Streaming"
+description: "Multi-turn conversations on llama.cpp with streaming, the correct sampling parameters for each LFM family, and prompt caching."
+---
+
+The quickest way to build a chat experience on llama.cpp is `llama-server`. It applies the model's chat template, exposes an OpenAI-compatible `/v1/chat/completions` endpoint, streams tokens over server-sent events, and reuses the KV cache across turns. Any OpenAI client library becomes your app-side API. For in-process use (mobile, or a desktop app that must not spawn a helper process) the same loop is a few dozen lines of the C API — see [Native C API](#native-c-api).
+
+## Start the server
+
+```bash
+llama-server -hf LiquidAI/LFM2.5-1.2B-Instruct-GGUF:Q4_K_M -c 4096 --port 8080 --jinja
+```
+
+- `-hf` downloads the GGUF from Hugging Face on first run; `:Q4_K_M` selects the quantization. Use `-m path/to/model.gguf` for a local file.
+- `-c` is the context length. Larger contexts cost memory linearly; check the model page for the supported maximum.
+- `--jinja` uses the chat template embedded in the GGUF. It is required for [tool calling](/deployment/on-device/llama-cpp/function-calling) and recommended for everything else.
+- `-ngl 99` offloads all layers to the GPU (Metal, CUDA, Vulkan) when one is available.
+- `-np 4` serves up to four requests concurrently; each slot gets `-c / 4` tokens of context.
+
+`GET /health` returns `{"status":"ok"}` once the model is loaded.
+
+## Sampling parameters
+
+Every LFM checkpoint has validated sampling defaults. Use them; placeholder values such as `temperature=0.7` degrade output quality.
+
+| Model family | `temperature` | `top_k` | `top_p` | `min_p` | `repeat_penalty` |
+|---|---|---|---|---|---|
+| LFM2.5-1.2B-Instruct | 0.1 | 50 | — | — | 1.05 |
+| LFM2.5-1.2B-Thinking | 0.1 | 50 | 0.1 | — | 1.05 |
+| LFM2.5-8B-A1B | 0.2 | 80 | — | — | 1.05 |
+| LFM2-24B-A2B | 0.1 | 50 | — | — | 1.05 |
+| LFM2 text, LFM2.5-JP | 0.3 | — | — | 0.15 | 1.05 |
+| LFM2-VL, LFM2.5-VL | 0.1 | — | — | 0.15 | 1.05 |
+
+
+`llama-server` reads the penalty as **`repeat_penalty`** in the request body (matching the `--repeat-penalty` CLI flag). `top_k`, `min_p`, and `repeat_penalty` are not part of the OpenAI schema, so pass them through `extra_body` in the OpenAI Python client. The exact values for any checkpoint are on its Hugging Face model card.
+
+
+## Send a message
+
+
+
+ ```python
+ from openai import OpenAI
+
+ client = OpenAI(base_url="http://localhost:8080/v1", api_key="not-needed")
+
+ response = client.chat.completions.create(
+ model="lfm2.5-1.2b-instruct", # any string; llama-server serves one model
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant."},
+ {"role": "user", "content": "What is machine learning?"},
+ ],
+ temperature=0.1,
+ max_tokens=512,
+ extra_body={"top_k": 50, "repeat_penalty": 1.05},
+ )
+ print(response.choices[0].message.content)
+ ```
+
+
+ ```bash
+ curl http://localhost:8080/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -d '{
+ "messages": [
+ {"role": "system", "content": "You are a helpful assistant."},
+ {"role": "user", "content": "What is machine learning?"}
+ ],
+ "temperature": 0.1,
+ "top_k": 50,
+ "repeat_penalty": 1.05,
+ "max_tokens": 512
+ }'
+ ```
+
+
+ ```javascript
+ const res = await fetch("http://localhost:8080/v1/chat/completions", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ messages: [
+ { role: "system", content: "You are a helpful assistant." },
+ { role: "user", content: "What is machine learning?" },
+ ],
+ temperature: 0.1,
+ top_k: 50,
+ repeat_penalty: 1.05,
+ max_tokens: 512,
+ }),
+ });
+ const data = await res.json();
+ console.log(data.choices[0].message.content);
+ ```
+
+
+
+## Stream tokens
+
+Set `stream: true` and consume the `delta.content` chunks as they arrive.
+
+
+
+ ```python
+ stream = client.chat.completions.create(
+ model="lfm2.5-1.2b-instruct",
+ messages=[{"role": "user", "content": "Write a haiku about the ocean."}],
+ temperature=0.1,
+ max_tokens=256,
+ extra_body={"top_k": 50, "repeat_penalty": 1.05},
+ stream=True,
+ )
+ for chunk in stream:
+ delta = chunk.choices[0].delta.content
+ if delta:
+ print(delta, end="", flush=True)
+ ```
+
+
+ ```javascript
+ const res = await fetch("http://localhost:8080/v1/chat/completions", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ messages: [{ role: "user", content: "Write a haiku about the ocean." }],
+ temperature: 0.1, top_k: 50, repeat_penalty: 1.05, max_tokens: 256,
+ stream: true,
+ }),
+ });
+
+ const reader = res.body.getReader();
+ const decoder = new TextDecoder();
+ let buffer = "";
+ while (true) {
+ const { value, done } = await reader.read();
+ if (done) break;
+ buffer += decoder.decode(value, { stream: true });
+ const lines = buffer.split("\n");
+ buffer = lines.pop();
+ for (const line of lines) {
+ if (!line.startsWith("data: ") || line === "data: [DONE]") continue;
+ const delta = JSON.parse(line.slice(6)).choices[0].delta.content;
+ if (delta) process.stdout.write(delta);
+ }
+ }
+ ```
+
+
+
+## Multi-turn conversations
+
+The API is stateless: send the whole `messages` history on every request and append the assistant's reply before the next turn.
+
+```python
+messages = [{"role": "system", "content": "You are a helpful assistant."}]
+
+def ask(user_text: str) -> str:
+ messages.append({"role": "user", "content": user_text})
+ response = client.chat.completions.create(
+ model="lfm2.5-1.2b-instruct",
+ messages=messages,
+ temperature=0.1,
+ max_tokens=512,
+ extra_body={"top_k": 50, "repeat_penalty": 1.05},
+ )
+ reply = response.choices[0].message.content
+ messages.append({"role": "assistant", "content": reply})
+ return reply
+
+print(ask("My name is Ada."))
+print(ask("What is my name?"))
+```
+
+Re-sending the history is cheap: `llama-server` keeps the KV cache of the previous request in its slot and only prefills the new suffix (`cache_prompt` defaults to `true`). Two flags make this more effective:
+
+- `--cache-reuse 256` — reuse cached chunks even when an earlier part of the prompt changed (for example, a trimmed history), by shifting KV entries instead of recomputing them.
+- `-np N` with `--slot-prompt-similarity` — with multiple slots, route each request to the slot whose cached prompt matches best; useful when several users share one server.
+
+To trim history, drop the oldest user/assistant pairs but keep the system message first. Long system prompts and RAG preambles are exactly what the prompt cache is for — keep them byte-identical across requests so the prefix stays cached.
+
+## Generation controls
+
+| Setting | Request field | CLI flag | Notes |
+|---|---|---|---|
+| Max new tokens | `max_tokens` | `-n` | Also `n_predict` on `/completion`. `-1` = until end-of-generation. |
+| Stop strings | `stop` | `-r` | Array of strings that end generation. |
+| Deterministic runs | `seed` | `-s` | Fixed seed + `temperature: 0` gives reproducible output on the same build/hardware. |
+| Per-request cache | `cache_prompt` | `--cache-prompt` | Default `true`. |
+| Timing info | `timings_per_token` | — | Adds prompt/decode timings to streamed chunks. |
+
+## Native C API
+
+In-process, the conversation loop is the same as in [iOS & Android](/deployment/on-device/llama-cpp/mobile#3-load-the-model-and-stream-a-response), with three additions:
+
+1. **Format only the new suffix.** Keep the message history and the formatted prompt string. For each turn, format the full history with the [LFM2 chat template](/lfm/key-concepts/chat-template) and tokenize only the part that was not already decoded. The KV cache still holds the earlier tokens, so prefill cost is proportional to the new turn.
+2. **Close the assistant turn.** The loop stops when `llama_vocab_is_eog()` fires, *before* the end token is decoded. Feed the tokens for `<|im_end|>\n` (with `parse_special = true`) after each reply so the cache matches what the template produces on the next turn.
+3. **Reset with `llama_memory_clear(llama_get_memory(ctx), true)`** to start a new conversation without reloading the model.
+
+```cpp
+// Per turn, after appending the user message to `history`:
+std::string suffix = format_lfm2(history) /* full template */ .substr(n_chars_already_decoded);
+std::vector
toks = tokenize(vocab, suffix, /*add_special=*/false, /*parse_special=*/true);
+llama_decode(ctx, llama_batch_get_one(toks.data(), toks.size()));
+// ... sample until llama_vocab_is_eog(vocab, tok), streaming pieces ...
+std::vector close = tokenize(vocab, "<|im_end|>\n", false, true);
+llama_decode(ctx, llama_batch_get_one(close.data(), close.size()));
+```
+
+[`examples/simple-chat/simple-chat.cpp`](https://github.com/ggml-org/llama.cpp/blob/master/examples/simple-chat/simple-chat.cpp) is the reference implementation of this pattern. If you need the full Jinja template (for example, tool definitions), link the `common` library and use `common_chat_templates_init()` / `common_chat_templates_apply()` from [`common/chat.h`](https://github.com/ggml-org/llama.cpp/blob/master/common/chat.h) instead of formatting by hand.
diff --git a/deployment/on-device/llama-cpp/desktop.mdx b/deployment/on-device/llama-cpp/desktop.mdx
new file mode 100644
index 00000000..077a7169
--- /dev/null
+++ b/deployment/on-device/llama-cpp/desktop.mdx
@@ -0,0 +1,244 @@
+---
+title: "Desktop & Server Apps"
+description: "Ship LFM models inside desktop applications and services with llama.cpp: llama-server as a sidecar, in-process bindings for Python, Node.js, and .NET, and hybrid local + cloud routing."
+---
+
+On laptops, desktops, and servers there are two ways to embed llama.cpp. Pick one per application:
+
+| Pattern | How it works | Choose it when |
+|---|---|---|
+| **Sidecar `llama-server`** | Your app launches the `llama-server` binary and talks to it over HTTP on localhost. | You want the full feature set (chat templates, tool calling, JSON schema, multimodal, prompt cache) with zero native build work, or your app is Electron, Tauri, .NET, Java, or Python. |
+| **In-process binding** | A language binding loads `libllama` into your process. | You cannot spawn a helper process, need the tightest latency, or want a single binary. |
+
+Both consume the same GGUF files from [Hugging Face](/lfm/models/complete-library), so you can switch later.
+
+## Sidecar: llama-server
+
+1. **Bundle the binary.** Download the prebuilt archive for each platform you ship from [llama.cpp releases](https://github.com/ggml-org/llama.cpp/releases) (`macos-arm64`, `win-cpu-x64` / `win-cuda-*`, `ubuntu-x64`, `ubuntu-vulkan-x64`, …) and place `llama-server` plus its shared libraries in your app's resources. See the [install guide](/deployment/on-device/llama-cpp#installation) for the binary matrix.
+2. **Launch it on startup** with a free port and the model path, and wait for `GET /health` to return `{"status":"ok"}`.
+3. **Call `/v1/chat/completions`** with any OpenAI client. Everything in [Chat & Streaming](/deployment/on-device/llama-cpp/chat), [Function Calling](/deployment/on-device/llama-cpp/function-calling), [Structured Output](/deployment/on-device/llama-cpp/structured-output), and [Vision & Audio](/deployment/on-device/llama-cpp/multimodal) applies unchanged.
+4. **Kill the child process** when your app exits.
+
+
+
+ ```javascript
+ import { spawn } from "node:child_process";
+ import path from "node:path";
+
+ const PORT = 8080;
+ const server = spawn(
+ path.join(process.resourcesPath, "bin", "llama-server"),
+ ["-m", modelPath, "-c", "4096", "--port", String(PORT), "--jinja", "-ngl", "99"],
+ { stdio: "ignore" }
+ );
+ process.on("exit", () => server.kill());
+
+ async function waitForServer() {
+ for (let i = 0; i < 300; i++) {
+ try {
+ const r = await fetch(`http://127.0.0.1:${PORT}/health`);
+ if (r.ok) return;
+ } catch {}
+ await new Promise((res) => setTimeout(res, 200));
+ }
+ throw new Error("llama-server did not start");
+ }
+ await waitForServer();
+
+ const res = await fetch(`http://127.0.0.1:${PORT}/v1/chat/completions`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ messages: [{ role: "user", content: "Summarize the benefits of on-device AI." }],
+ temperature: 0.1, top_k: 50, repeat_penalty: 1.05, max_tokens: 512,
+ }),
+ });
+ console.log((await res.json()).choices[0].message.content);
+ ```
+
+
+ ```python
+ import subprocess, time, requests
+ from openai import OpenAI
+
+ PORT = 8080
+ server = subprocess.Popen(
+ ["llama-server", "-m", model_path, "-c", "4096", "--port", str(PORT), "--jinja", "-ngl", "99"],
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
+ )
+ for _ in range(300):
+ try:
+ if requests.get(f"http://127.0.0.1:{PORT}/health", timeout=1).ok:
+ break
+ except requests.RequestException:
+ time.sleep(0.2)
+
+ client = OpenAI(base_url=f"http://127.0.0.1:{PORT}/v1", api_key="not-needed")
+ response = client.chat.completions.create(
+ model="lfm2.5-1.2b-instruct",
+ messages=[{"role": "user", "content": "Summarize the benefits of on-device AI."}],
+ temperature=0.1, max_tokens=512,
+ extra_body={"top_k": 50, "repeat_penalty": 1.05},
+ )
+ print(response.choices[0].message.content)
+ server.terminate()
+ ```
+
+
+ ```csharp
+ using System.Diagnostics;
+ using System.Net.Http.Json;
+ using System.Text.Json;
+
+ var server = Process.Start(new ProcessStartInfo("llama-server",
+ $"-m \"{modelPath}\" -c 4096 --port 8080 --jinja -ngl 99")
+ { UseShellExecute = false, CreateNoWindow = true });
+ AppDomain.CurrentDomain.ProcessExit += (_, _) => server?.Kill();
+
+ var http = new HttpClient { BaseAddress = new Uri("http://127.0.0.1:8080") };
+ while (!(await http.GetAsync("/health")).IsSuccessStatusCode) await Task.Delay(200);
+
+ var response = await http.PostAsJsonAsync("/v1/chat/completions", new
+ {
+ messages = new[] { new { role = "user", content = "Summarize the benefits of on-device AI." } },
+ temperature = 0.1,
+ top_k = 50,
+ repeat_penalty = 1.05,
+ max_tokens = 512,
+ });
+ using var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
+ Console.WriteLine(json.RootElement.GetProperty("choices")[0]
+ .GetProperty("message").GetProperty("content").GetString());
+ ```
+
+ The official OpenAI .NET client also works against `llama-server`; use raw `HttpClient` (as above) when you need llama.cpp-only fields such as `top_k` and `repeat_penalty`.
+
+
+
+Complete sample applications built this way:
+
+- [Electron / Node.js example](https://github.com/Liquid4All/leap-llamacpp-electron-example)
+- [Python example](https://github.com/Liquid4All/leap-llamacpp-python-example)
+- [C# example](https://github.com/Liquid4All/leap-llamacpp-csharp-example)
+
+## In-process bindings
+
+
+
+ ```bash
+ pip install llama-cpp-python # add CMAKE_ARGS="-DGGML_METAL=on" / "-DGGML_CUDA=on" for GPU builds
+ ```
+
+ ```python
+ from llama_cpp import Llama
+
+ llm = Llama.from_pretrained(
+ repo_id="LiquidAI/LFM2.5-1.2B-Instruct-GGUF",
+ filename="*Q4_K_M.gguf",
+ n_ctx=4096,
+ n_gpu_layers=-1,
+ )
+
+ for chunk in llm.create_chat_completion(
+ messages=[{"role": "user", "content": "What is machine learning?"}],
+ temperature=0.1, top_k=50, repeat_penalty=1.05, max_tokens=512,
+ stream=True,
+ ):
+ delta = chunk["choices"][0]["delta"].get("content")
+ if delta:
+ print(delta, end="", flush=True)
+ ```
+
+ `create_chat_completion` mirrors the OpenAI request shape (`messages`, `tools`, `response_format`, `stream`). The package bundles its own llama.cpp build, so upgrade it to pick up new architectures.
+
+
+ ```bash
+ npm install node-llama-cpp # prebuilt binaries for macOS, Linux, Windows; Metal/CUDA/Vulkan auto-detected
+ ```
+
+ ```typescript
+ import { getLlama, LlamaChatSession, resolveModelFile } from "node-llama-cpp";
+
+ const llama = await getLlama();
+ const modelPath = await resolveModelFile(
+ "hf:LiquidAI/LFM2.5-1.2B-Instruct-GGUF/LFM2.5-1.2B-Instruct-Q4_K_M.gguf", "./models");
+ const model = await llama.loadModel({ modelPath });
+ const context = await model.createContext({ contextSize: 4096 });
+ const session = new LlamaChatSession({ contextSequence: context.getSequence() });
+
+ await session.prompt("What is machine learning?", {
+ temperature: 0.1,
+ topK: 50,
+ repeatPenalty: { penalty: 1.05 },
+ onTextChunk: (text) => process.stdout.write(text),
+ });
+ ```
+
+ `LlamaChatSession` keeps the conversation and KV cache between `prompt()` calls. Function calling (`functions:` with `defineChatSessionFunction`) and JSON-schema grammars (`llama.createGrammarForJsonSchema`) are built in.
+
+
+ ```bash
+ dotnet add package LLamaSharp
+ dotnet add package LLamaSharp.Backend.Cpu # or .Cuda12 / .Vulkan / .Metal
+ ```
+
+ ```csharp
+ using LLama;
+ using LLama.Common;
+ using LLama.Sampling;
+
+ var parameters = new ModelParams(modelPath) { ContextSize = 4096, GpuLayerCount = 99 };
+ using var model = LLamaWeights.LoadFromFile(parameters);
+ using var context = model.CreateContext(parameters);
+ var executor = new InteractiveExecutor(context);
+ var session = new ChatSession(executor);
+
+ var inference = new InferenceParams
+ {
+ MaxTokens = 512,
+ SamplingPipeline = new DefaultSamplingPipeline { Temperature = 0.1f, TopK = 50, RepeatPenalty = 1.05f },
+ };
+ await foreach (var text in session.ChatAsync(
+ new ChatHistory.Message(AuthorRole.User, "What is machine learning?"), inference))
+ {
+ Console.Write(text);
+ }
+ ```
+
+
+
+Other maintained bindings — Rust (`llama-cpp-2`), Go (`go-llama.cpp`), Java (`java-llama.cpp`), Dart/Flutter, and more — are listed in the [llama.cpp README](https://github.com/ggml-org/llama.cpp?tab=readme-ov-file#description).
+
+## Hybrid on-device + cloud routing
+
+Because `llama-server` speaks the OpenAI protocol, one client can target a local model and a cloud model interchangeably: route short, latency-sensitive, or private prompts to the local endpoint and fall back to a hosted deployment (for example [vLLM](/deployment/gpu-inference/vllm) or a [cloud provider](/deployment/gpu-inference/modal)) for the rest.
+
+```python
+import os
+from openai import OpenAI
+
+local = OpenAI(base_url="http://127.0.0.1:8080/v1", api_key="not-needed")
+cloud = OpenAI(base_url="https://your-vllm-host/v1", api_key=os.environ["CLOUD_API_KEY"])
+
+def complete(messages, prefer_local=True):
+ if prefer_local:
+ client, model = local, "lfm2.5-1.2b-instruct"
+ extra = {"top_k": 50, "repeat_penalty": 1.05} # llama.cpp field name
+ else:
+ client, model = cloud, "LiquidAI/LFM2.5-8B-A1B"
+ extra = {"top_k": 80, "repetition_penalty": 1.05} # vLLM / SGLang field name
+ return client.chat.completions.create(
+ model=model, messages=messages, temperature=0.1 if prefer_local else 0.2,
+ max_tokens=512, extra_body=extra,
+ )
+```
+
+The `messages` format, tool definitions, and streaming code are identical on both sides — only the base URL and the penalty field name (`repeat_penalty` for llama.cpp, `repetition_penalty` for vLLM/SGLang) differ.
+
+## Packaging checklist
+
+- **Model download on first launch**, not at install time: GGUF files are hundreds of MB to several GB. Show progress, verify the file size, and store it in the user data directory.
+- **Use `-hf` only in development.** In production pin the exact file (`-m`) so a model-card update cannot change behavior under your users.
+- **Choose the binary per machine.** CPU builds run everywhere; ship GPU variants (Metal is built into the macOS binary; CUDA / Vulkan on Windows and Linux) when you have tested them.
+- **Memory-map, don't read.** llama.cpp uses `mmap` by default; keep the model on local disk (not a network share) for fast cold starts.
+- **Benchmark with `llama-bench`** on representative hardware before deciding on quantization and context size. See [Hardware Evaluation](/guides/hardware-evaluation).
diff --git a/deployment/on-device/llama-cpp/function-calling.mdx b/deployment/on-device/llama-cpp/function-calling.mdx
new file mode 100644
index 00000000..e7700256
--- /dev/null
+++ b/deployment/on-device/llama-cpp/function-calling.mdx
@@ -0,0 +1,141 @@
+---
+title: "Function Calling & Agents"
+description: "Tool use with LFM2.5 on llama.cpp: OpenAI-style tools through llama-server, the agent loop, and how LFM tool-call tokens are parsed."
+---
+
+LFM2 and LFM2.5 emit tool calls between `<|tool_call_start|>` and `<|tool_call_end|>` control tokens (see [Tool Use](/lfm/key-concepts/tool-use)). llama.cpp ships a dedicated parser for both formats: start `llama-server` with `--jinja`, pass `tools` in the request, and tool calls come back as structured `tool_calls` on the OpenAI-compatible response. There is nothing to parse on the client.
+
+## Start the server
+
+```bash
+llama-server -hf LiquidAI/LFM2.5-1.2B-Instruct-GGUF:Q4_K_M -c 8192 --port 8080 --jinja
+```
+
+`--jinja` is mandatory: it renders the tool definitions through the model's chat template and enables tool-call parsing. Use a recent llama.cpp release — LFM2/LFM2.5 template detection lives in `common/chat.cpp` and older builds fall back to a generic parser.
+
+## Define tools and make a call
+
+Tools use the OpenAI JSON schema format. Passing them in the `tools` field is all the model needs; do not also paste them into the system prompt.
+
+```python
+import json
+from openai import OpenAI
+
+client = OpenAI(base_url="http://localhost:8080/v1", api_key="not-needed")
+
+tools = [{
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "Get the current weather for a city.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "city": {"type": "string", "description": "City name, e.g. 'Paris'"},
+ "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
+ },
+ "required": ["city"],
+ },
+ },
+}]
+
+messages = [{"role": "user", "content": "What's the weather like in Paris right now?"}]
+
+response = client.chat.completions.create(
+ model="lfm2.5-1.2b-instruct",
+ messages=messages,
+ tools=tools,
+ tool_choice="auto",
+ temperature=0.1,
+ max_tokens=512,
+ extra_body={"top_k": 50, "repeat_penalty": 1.05},
+)
+
+message = response.choices[0].message
+for call in message.tool_calls or []:
+ print(call.function.name, json.loads(call.function.arguments))
+# get_weather {'city': 'Paris'}
+```
+
+`finish_reason` is `"tool_calls"` when the model asked for a tool. `tool_choice` accepts `"auto"`, `"none"`, `"required"`, or a specific function.
+
+## The agent loop
+
+An agent is a loop: send the conversation, execute any tool calls, append the results as `tool` messages, and call the model again until it answers in plain text.
+
+```python
+def get_weather(city: str, unit: str = "celsius") -> dict:
+ # Replace with a real API call.
+ return {"city": city, "temperature": 21, "unit": unit, "condition": "sunny"}
+
+TOOL_IMPLS = {"get_weather": get_weather}
+
+def run_agent(user_text: str, max_steps: int = 5) -> str:
+ messages = [
+ {"role": "system", "content": "You are a helpful assistant. Use tools when they help."},
+ {"role": "user", "content": user_text},
+ ]
+ for _ in range(max_steps):
+ response = client.chat.completions.create(
+ model="lfm2.5-1.2b-instruct",
+ messages=messages,
+ tools=tools,
+ temperature=0.1,
+ max_tokens=512,
+ extra_body={"top_k": 50, "repeat_penalty": 1.05},
+ )
+ message = response.choices[0].message
+ messages.append(message) # keep the assistant turn (incl. tool_calls)
+
+ if not message.tool_calls:
+ return message.content # final answer
+
+ for call in message.tool_calls: # LFM2.5 may request several calls at once
+ args = json.loads(call.function.arguments)
+ result = TOOL_IMPLS[call.function.name](**args)
+ messages.append({
+ "role": "tool",
+ "tool_call_id": call.id,
+ "content": json.dumps(result),
+ })
+ return "Stopped after too many tool calls."
+
+print(run_agent("What's the weather like in Paris right now?"))
+```
+
+Guidelines that matter on small on-device models:
+
+- **Keep the tool list short and the descriptions precise.** Every tool adds prompt tokens on every turn; 3–8 well-described tools work far better than 30 vague ones.
+- **Return compact results.** Serialize only the fields the model needs; large JSON blobs consume context and dilute attention.
+- **Cap the loop.** Always bound the number of steps and handle unknown tool names or malformed arguments by returning an error message in the `tool` result rather than crashing.
+- **Use the recommended sampling.** Tool arguments are structured text; `temperature 0.1` keeps them well-formed.
+- **Prompt caching does the heavy lifting.** The system prompt and tool definitions are identical every step, so `llama-server` prefills them once per conversation.
+
+## Streaming tool calls
+
+With `stream: true`, tool calls arrive incrementally in `choices[0].delta.tool_calls` (`index`, `id`, `function.name`, then chunks of `function.arguments`). Accumulate the argument fragments per `index` and parse the JSON once `finish_reason` is `"tool_calls"`.
+
+## Pythonic and JSON tool-call formats
+
+LFM2.5 natively writes Pythonic calls (`get_weather(city="Paris")`); LFM2 wraps definitions in `<|tool_list_start|>` / `<|tool_list_end|>`. With `--jinja`, `llama-server` detects the template and normalizes either format into OpenAI `tool_calls`, so you never see the raw tokens. If you disable tool parsing (`parse_tool_calls: false` in the request) the raw `<|tool_call_start|>…<|tool_call_end|>` text is returned in `content` instead.
+
+## In-process (no server)
+
+If you embed llama.cpp directly (for example on [iOS & Android](/deployment/on-device/llama-cpp/mobile)), link the `common` library and use the same machinery `llama-server` uses:
+
+- `common_chat_templates_init(model, "")` loads the GGUF's Jinja template.
+- `common_chat_templates_apply(tmpls, inputs)` renders messages **and** tool definitions to a prompt, and returns the grammar/trigger configuration for the format.
+- `common_chat_parse(text, is_partial, params)` turns the generated text into a `common_chat_msg` with `tool_calls`.
+
+See [`common/chat.h`](https://github.com/ggml-org/llama.cpp/blob/master/common/chat.h) for the full API. Alternatively, format the prompt yourself following [Tool Use](/lfm/key-concepts/tool-use) and split on the `<|tool_call_start|>` / `<|tool_call_end|>` tokens (`llama_token_to_piece` with `special = true` so the control tokens are not filtered out).
+
+## Next steps
+
+
+
+ Force valid JSON for tool arguments or final answers.
+
+
+ How LFM2.5 represents tools and calls at the token level.
+
+
diff --git a/deployment/on-device/llama-cpp/migrating-from-leap-sdk.mdx b/deployment/on-device/llama-cpp/migrating-from-leap-sdk.mdx
new file mode 100644
index 00000000..d6e409d1
--- /dev/null
+++ b/deployment/on-device/llama-cpp/migrating-from-leap-sdk.mdx
@@ -0,0 +1,52 @@
+---
+title: "Migrating from LEAP SDK"
+description: "The LEAP SDK is deprecated. This page maps each LEAP SDK concept to its native llama.cpp equivalent."
+---
+
+
+The **LEAP SDK is deprecated** and no longer receives new releases. It was a Kotlin Multiplatform wrapper around llama.cpp; everything it did is available directly from llama.cpp, which supports LFM2 / LFM2.5 models, LFM2-VL projectors, and LFM2 tool-call parsing upstream. Existing LEAP SDK artifacts remain on Maven Central and GitHub, and the archived reference is at [LEAP SDK (archived)](/deployment/on-device/sdk/overview).
+
+
+## Concept mapping
+
+| LEAP SDK | llama.cpp equivalent | Guide |
+|---|---|---|
+| `LeapModelDownloader.loadModel(modelName:, quantizationType:)`, LEAP Model Library bundles | Download the GGUF from Hugging Face (`LiquidAI/-GGUF`) with your platform's downloader; `llama-server -hf :` on desktop | [iOS & Android](/deployment/on-device/llama-cpp/mobile#2-get-a-model-onto-the-device) |
+| `ModelRunner` | `llama_model` + `llama_context` (C API) or a running `llama-server` | [iOS & Android](/deployment/on-device/llama-cpp/mobile), [Desktop & Server Apps](/deployment/on-device/llama-cpp/desktop) |
+| `Conversation`, `ChatMessage` | An OpenAI-style `messages` array; the chat template is applied by `llama-server --jinja` or by your code | [Chat & Streaming](/deployment/on-device/llama-cpp/chat) |
+| `conversation.generateResponse(...)` streaming `MessageResponse.Chunk` | `stream: true` on `/v1/chat/completions`, or the `llama_decode` / `llama_sampler_sample` loop | [Chat & Streaming](/deployment/on-device/llama-cpp/chat) |
+| `GenerationOptions` (`temperature`, `topK`, `minP`, `repetitionPenalty`, `maxTokens`) | Request fields `temperature`, `top_k`, `min_p`, `repeat_penalty`, `max_tokens`; `llama_sampler_init_*` in the C API | [Sampling parameters](/deployment/on-device/llama-cpp/chat#sampling-parameters) |
+| Per-checkpoint sampler defaults from the bundle manifest | Values on each Hugging Face model card (summarized in the sampling table) | [Sampling parameters](/deployment/on-device/llama-cpp/chat#sampling-parameters) |
+| `LeapFunction`, `MessageResponse.FunctionCalls`, `LFMFunctionCallParser` / `HermesFunctionCallParser` | OpenAI `tools` / `tool_calls` with `llama-server --jinja` (LFM2 and LFM2.5 formats parsed natively); `common_chat_parse()` in-process | [Function Calling & Agents](/deployment/on-device/llama-cpp/function-calling) |
+| `@Generatable` / `@Guide` constrained generation, `jsonSchema` in `GenerationOptions` | `response_format: {"type": "json_schema", ...}` or a GBNF `grammar`; `llama_sampler_init_grammar()` in the C API | [Structured Output](/deployment/on-device/llama-cpp/structured-output) |
+| `ChatMessageContent.Image` (JPEG bytes) | `image_url` content part with a base64 `data:` URI; `mtmd` API in-process, with the model's `mmproj-*.gguf` | [Vision & Audio](/deployment/on-device/llama-cpp/multimodal) |
+| `ChatMessageContent.Audio` (WAV) and `MessageResponse.AudioSample` | Liquid's `llama-liquid-audio-cli` / `llama-liquid-audio-server` runners for LFM2.5-Audio | [Vision & Audio](/deployment/on-device/llama-cpp/multimodal#audio-lfm25-audio) |
+| `CacheOptions` / KV cache reuse | `cache_prompt` (default on) and `--cache-reuse` in `llama-server`; keep the context alive between turns in the C API | [Multi-turn conversations](/deployment/on-device/llama-cpp/chat#multi-turn-conversations) |
+| `ModelLoadingOptions` (`nCtx`, `nThreads`, `nGpuLayers`, `useMmap`) | `llama_context_params.n_ctx` / `n_threads`, `llama_model_params.n_gpu_layers` / `use_mmap`; `-c`, `-t`, `-ngl` flags | [Tune for mobile](/deployment/on-device/llama-cpp/mobile#4-tune-for-mobile) |
+| `leap-openai-client` (hybrid on-device + cloud) | Any OpenAI client pointed at `llama-server` locally and a hosted endpoint remotely | [Hybrid routing](/deployment/on-device/llama-cpp/desktop#hybrid-on-device--cloud-routing) |
+| `leap-ui` voice assistant widget | No drop-in replacement. Pair the audio runner with your platform's recording/playback APIs. | [Vision & Audio](/deployment/on-device/llama-cpp/multimodal#audio-lfm25-audio) |
+| Desktop targets (JVM, Kotlin/Native, Windows, Linux) | `llama-server` sidecar or a binding for your language (Python, Node.js, .NET, Rust, Go, Java) | [Desktop & Server Apps](/deployment/on-device/llama-cpp/desktop) |
+
+## Platform notes
+
+
+
+ Replace the `LeapSDK` Swift package with `llama.xcframework` from a [llama.cpp release](https://github.com/ggml-org/llama.cpp/releases) and call the C API directly (`import llama`). Metal is enabled in the prebuilt framework. The minimum deployment target drops to iOS 16.4 / macOS 13.3. See [iOS & Android](/deployment/on-device/llama-cpp/mobile).
+
+
+ Replace the `ai.liquid.leap:*` Maven dependencies with llama.cpp built through the NDK — either the upstream [`examples/llama.android`](https://github.com/ggml-org/llama.cpp/tree/master/examples/llama.android) library module or your own CMake/JNI wrapper. Model downloads move to `WorkManager` / `DownloadManager`. See [iOS & Android](/deployment/on-device/llama-cpp/mobile).
+
+
+ Launch `llama-server` as a sidecar process or use an in-process binding. The OpenAI-compatible API gives you chat, streaming, tools, and JSON schema without any native code. See [Desktop & Server Apps](/deployment/on-device/llama-cpp/desktop).
+
+
+
+## Models and bundles
+
+LEAP SDK loaded "bundles" (a GGUF plus a manifest with companion files) from the LEAP Model Library. The same weights are published as plain GGUF on Hugging Face under [LiquidAI](https://huggingface.co/LiquidAI): the language model file, plus `mmproj-*` for vision models and the encoder / vocoder / tokenizer files for audio models. If you already have downloaded bundles, the `.gguf` files inside them load directly in llama.cpp.
+
+Fine-tuned models continue to work: convert them with `convert_hf_to_gguf.py` as described in [Converting Custom Models](/deployment/on-device/llama-cpp#converting-custom-models).
+
+## Archived reference
+
+The LEAP SDK pages remain online for teams still shipping the SDK but are no longer maintained: [Overview](/deployment/on-device/sdk/overview), [Quick Start](/deployment/on-device/sdk/quick-start), [Changelog](/deployment/on-device/leap-sdk-changelog). The Android example apps under [Examples](/examples/index#android) were built with the LEAP SDK and are kept as architectural references.
diff --git a/deployment/on-device/llama-cpp/mobile.mdx b/deployment/on-device/llama-cpp/mobile.mdx
new file mode 100644
index 00000000..044a47ab
--- /dev/null
+++ b/deployment/on-device/llama-cpp/mobile.mdx
@@ -0,0 +1,264 @@
+---
+title: "iOS & Android"
+description: "Embed llama.cpp directly in an iOS or Android app and run LFM GGUF models on-device through the native C API."
+---
+
+llama.cpp is a dependency-free C/C++ library, so it links straight into a mobile app. Every LFM checkpoint ships as GGUF on Hugging Face ([LiquidAI](https://huggingface.co/LiquidAI)), and upstream llama.cpp supports the LFM2 architecture, LFM2-VL projectors, and LFM2/LFM2.5 tool-call parsing. No wrapper SDK is required.
+
+
+On a phone, run the library **in-process** through the C API as shown here. `llama-server` is the right tool on laptops, desktops, and servers — see [Desktop & Server Apps](/deployment/on-device/llama-cpp/desktop).
+
+
+## 1. Add llama.cpp to your project
+
+
+
+ Every llama.cpp release publishes a prebuilt `llama.xcframework` with slices for iOS (device and simulator), macOS, visionOS, and tvOS. It is built with Metal enabled and includes the `mtmd` multimodal library.
+
+ 1. Download `llama--xcframework.zip` from [llama.cpp releases](https://github.com/ggml-org/llama.cpp/releases) and unzip it.
+ 2. In Xcode, drag `llama.xcframework` into your target's **Frameworks, Libraries, and Embedded Content**.
+ 3. `import llama` in Swift. The C API is exposed directly; no bridging header is needed.
+
+ The prebuilt framework targets iOS 16.4+ and macOS 13.3+. To build it yourself (for example, to change the minimum OS version or drop slices):
+
+ ```bash
+ git clone https://github.com/ggml-org/llama.cpp
+ cd llama.cpp
+ ./build-xcframework.sh # output: build-apple/llama.xcframework
+ ```
+
+ The upstream [`llama.swiftui`](https://github.com/ggml-org/llama.cpp/tree/master/examples/llama.swiftui) example is a complete SwiftUI chat app built this way.
+
+
+ llama.cpp ships an Android Studio project at [`examples/llama.android`](https://github.com/ggml-org/llama.cpp/tree/master/examples/llama.android). Its `lib` module compiles llama.cpp with CMake through the NDK, includes CPU kernels up to Arm SME2 with runtime feature detection, and exposes a small Kotlin API (`AiChat` / `InferenceEngine`). Import the directory into Android Studio, run a Gradle sync, and depend on the `lib` module from your app (or copy it into your project).
+
+ If you prefer to own the JNI layer, add llama.cpp as a CMake subdirectory of your native module:
+
+ ```cmake
+ # app/src/main/cpp/CMakeLists.txt
+ cmake_minimum_required(VERSION 3.22)
+ project(myapp)
+
+ set(LLAMA_BUILD_COMMON OFF)
+ set(LLAMA_BUILD_TESTS OFF)
+ set(LLAMA_BUILD_EXAMPLES OFF)
+ set(LLAMA_BUILD_TOOLS OFF)
+ set(LLAMA_BUILD_SERVER OFF)
+ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/llama.cpp build-llama)
+
+ add_library(myapp SHARED myapp.cpp)
+ target_link_libraries(myapp llama android log)
+ ```
+
+ ```kotlin
+ // app/build.gradle.kts
+ android {
+ defaultConfig {
+ ndk { abiFilters += listOf("arm64-v8a") }
+ }
+ externalNativeBuild {
+ cmake { path = file("src/main/cpp/CMakeLists.txt") }
+ }
+ }
+ ```
+
+ Prebuilt `llama--bin-android-arm64.tar.gz` archives on the [releases page](https://github.com/ggml-org/llama.cpp/releases) contain `llama-cli`, `llama-server`, and `llama-bench` for quick testing on a device over `adb` or in Termux. See [docs/android.md](https://github.com/ggml-org/llama.cpp/blob/master/docs/android.md) for the Termux and NDK cross-compile recipes.
+
+
+
+## 2. Get a model onto the device
+
+Download a GGUF from Hugging Face at first launch and keep it in app-private storage. llama.cpp memory-maps the file, so it must be a real file on disk — not a compressed asset.
+
+```
+https://huggingface.co/LiquidAI/LFM2.5-1.2B-Instruct-GGUF/resolve/main/LFM2.5-1.2B-Instruct-Q4_0.gguf
+```
+
+- Use `URLSessionConfiguration.background(withIdentifier:)` on iOS and `WorkManager` (or `DownloadManager`) on Android so downloads survive backgrounding.
+- **`Q4_0`** is the best default on phones: it is the smallest quantization and llama.cpp repacks it into Arm-optimized kernels at load time. Use `Q4_K_M` when you want slightly better quality on capable devices. See [Model Library](/lfm/models/complete-library) for every GGUF repository.
+- For vision models also download the matching `mmproj-*.gguf` from the same repository (see [Vision & Audio](/deployment/on-device/llama-cpp/multimodal)).
+
+For development you can push a file directly:
+
+```bash
+uv pip install huggingface-hub
+hf download LiquidAI/LFM2.5-1.2B-Instruct-GGUF LFM2.5-1.2B-Instruct-Q4_0.gguf --local-dir .
+adb push LFM2.5-1.2B-Instruct-Q4_0.gguf /data/local/tmp/ # Android
+```
+
+## 3. Load the model and stream a response
+
+The generation loop is the same on every platform: load the model, create a context, build a sampler chain with the model's [sampling parameters](/deployment/on-device/llama-cpp/chat#sampling-parameters), format the prompt with the [chat template](/lfm/key-concepts/chat-template), then decode and sample one token at a time.
+
+
+
+ ```swift
+ import Foundation
+ import llama
+
+ enum RunnerError: Error { case modelLoadFailed, contextInitFailed }
+
+ /// Minimal llama.cpp runner for LFM2.5-1.2B-Instruct.
+ final class LFMRunner {
+ private let model: OpaquePointer
+ private let ctx: OpaquePointer
+ private let vocab: OpaquePointer
+ private let sampler: OpaquePointer
+
+ init(modelPath: String, contextLength: UInt32 = 4096) throws {
+ llama_backend_init()
+
+ var modelParams = llama_model_default_params()
+ modelParams.n_gpu_layers = 99 // offload to Metal; set 0 for CPU-only
+ guard let model = llama_model_load_from_file(modelPath, modelParams) else {
+ throw RunnerError.modelLoadFailed
+ }
+ self.model = model
+ self.vocab = llama_model_get_vocab(model)
+
+ var ctxParams = llama_context_default_params()
+ ctxParams.n_ctx = contextLength
+ ctxParams.n_batch = 512
+ ctxParams.n_threads = Int32(max(1, ProcessInfo.processInfo.activeProcessorCount - 2))
+ ctxParams.n_threads_batch = ctxParams.n_threads
+ guard let ctx = llama_init_from_model(model, ctxParams) else {
+ throw RunnerError.contextInitFailed
+ }
+ self.ctx = ctx
+
+ // LFM2.5-1.2B-Instruct: temperature 0.1, top_k 50, repetition penalty 1.05
+ let sampler = llama_sampler_chain_init(llama_sampler_chain_default_params())
+ llama_sampler_chain_add(sampler, llama_sampler_init_top_k(50))
+ llama_sampler_chain_add(sampler, llama_sampler_init_penalties(
+ llama_vocab_n_tokens(vocab), 64, 1.05, 0.0, 0.0))
+ llama_sampler_chain_add(sampler, llama_sampler_init_temp(0.1))
+ llama_sampler_chain_add(sampler, llama_sampler_init_dist(UInt32.max)) // random seed
+ self.sampler = sampler!
+ }
+
+ deinit {
+ llama_sampler_free(sampler)
+ llama_free(ctx)
+ llama_model_free(model)
+ llama_backend_free()
+ }
+
+ /// Formats one user turn with the LFM2 chat template and streams the reply.
+ func generate(system: String = "You are a helpful assistant.",
+ user: String,
+ maxTokens: Int = 512,
+ onText: (String) -> Void) {
+ llama_memory_clear(llama_get_memory(ctx), true) // start a fresh conversation
+
+ let prompt = """
+ <|im_start|>system
+ \(system)<|im_end|>
+ <|im_start|>user
+ \(user)<|im_end|>
+ <|im_start|>assistant
+
+ """
+ var tokens = tokenize(prompt, addBOS: true) // addBOS prepends <|startoftext|>
+ var pending: [UInt8] = []
+
+ var rc = tokens.withUnsafeMutableBufferPointer { buf in
+ llama_decode(ctx, llama_batch_get_one(buf.baseAddress, Int32(buf.count)))
+ }
+ for _ in 0..
+
+ pending += piece(next)
+ if let text = String(bytes: pending, encoding: .utf8) { // wait for complete UTF-8 sequences
+ onText(text)
+ pending.removeAll()
+ }
+ rc = withUnsafeMutablePointer(to: &next) { p in
+ llama_decode(ctx, llama_batch_get_one(p, 1))
+ }
+ }
+ }
+
+ private func tokenize(_ text: String, addBOS: Bool) -> [llama_token] {
+ let byteCount = Int32(text.utf8.count)
+ var tokens = [llama_token](repeating: 0, count: Int(byteCount) + 2)
+ let n = llama_tokenize(vocab, text, byteCount, &tokens, Int32(tokens.count), addBOS, true)
+ return n < 0 ? [] : Array(tokens.prefix(Int(n)))
+ }
+
+ /// Raw UTF-8 bytes for a token; special/control tokens are filtered out (`special: false`).
+ private func piece(_ token: llama_token) -> [UInt8] {
+ var buf = [CChar](repeating: 0, count: 256)
+ let n = llama_token_to_piece(vocab, token, &buf, Int32(buf.count), 0, false)
+ return n <= 0 ? [] : buf.prefix(Int(n)).map { UInt8(bitPattern: $0) }
+ }
+ }
+ ```
+
+ Usage from a view model:
+
+ ```swift
+ let runner = try LFMRunner(modelPath: modelURL.path)
+ Task.detached {
+ runner.generate(user: "What is machine learning?") { text in
+ Task { @MainActor in self.output += text }
+ }
+ }
+ ```
+
+
+ With the upstream `examples/llama.android` `lib` module:
+
+ ```kotlin
+ import com.arm.aichat.AiChat
+ import java.io.File
+
+ val engine = AiChat.getInferenceEngine(applicationContext)
+
+ lifecycleScope.launch {
+ engine.loadModel(File(filesDir, "LFM2.5-1.2B-Instruct-Q4_0.gguf").absolutePath)
+ engine.setSystemPrompt("You are a helpful assistant.")
+
+ engine.sendUserPrompt("What is machine learning?", predictLength = 512)
+ .collect { piece -> appendToUi(piece) } // Flow of generated text
+ }
+ ```
+
+ `InferenceEngine` applies the model's chat template, manages the KV cache across turns, and exposes a `state: StateFlow` you can bind to your UI (`LoadingModel`, `ModelReady`, `Generating`, …). Call `engine.cleanUp()` to reset the conversation and `engine.destroy()` when you are done.
+
+
+ The binding's sampler is configured in `lib/src/main/cpp/ai_chat.cpp` (`new_sampler`, default temperature 0.3). Set it to the values for your model — for LFM2.5-1.2B-Instruct: `temp = 0.1`, `top_k = 50`, `penalty_repeat = 1.05` — or expose those fields through the JNI layer.
+
+
+ If you write your own JNI wrapper, the C++ side is the same sequence as the Swift example: `llama_model_load_from_file` → `llama_init_from_model` → sampler chain → `llama_tokenize` → `llama_decode` / `llama_sampler_sample` loop. [`examples/simple/simple.cpp`](https://github.com/ggml-org/llama.cpp/blob/master/examples/simple/simple.cpp) and [`examples/simple-chat/simple-chat.cpp`](https://github.com/ggml-org/llama.cpp/blob/master/examples/simple-chat/simple-chat.cpp) are the canonical reference implementations.
+
+
+
+For multi-turn conversations, prompt-cache reuse, and how to keep the KV cache aligned with the chat template, see [Chat & Streaming](/deployment/on-device/llama-cpp/chat#native-c-api).
+
+## 4. Tune for mobile
+
+- **Memory.** Weights are memory-mapped by default (`use_mmap = true`), so they count as file-backed pages rather than app RSS — iOS jetsam and Android LMK treat them far more leniently. Keep `n_ctx` as small as the use case allows; the KV cache scales linearly with it.
+- **Threads.** Use the performance cores only: `n_threads = activeProcessorCount - 2` is a good starting point. More threads than physical big cores usually slows decoding.
+- **GPU.** On Apple devices set `n_gpu_layers = 99` to run on Metal. On Android, CPU is the safe default; Vulkan and OpenCL (Adreno) backends exist but need device-specific testing.
+- **Quantization.** `Q4_0` for the smallest footprint and fastest Arm kernels; `Q4_K_M` when quality matters more than a few hundred MB.
+- **Vision and audio.** The XCFramework includes `mtmd`; on Android enable `LLAMA_BUILD_MTMD`. See [Vision & Audio](/deployment/on-device/llama-cpp/multimodal).
+- **Benchmark on hardware.** `llama-bench -m model.gguf -p 512 -n 128` from the prebuilt Android or macOS binaries gives prefill/decode tokens-per-second before you write any app code. See [Hardware Evaluation](/guides/hardware-evaluation).
+
+## Next steps
+
+
+
+ Multi-turn conversations, sampling parameters, prompt caching.
+
+
+ Constrain generation to a JSON schema or GBNF grammar.
+
+
+ Tool use with LFM2.5's native tool-call parser.
+
+
+ Run LFM2.5-VL and LFM2.5-Audio on llama.cpp.
+
+
diff --git a/deployment/on-device/llama-cpp/multimodal.mdx b/deployment/on-device/llama-cpp/multimodal.mdx
new file mode 100644
index 00000000..c7f03cb6
--- /dev/null
+++ b/deployment/on-device/llama-cpp/multimodal.mdx
@@ -0,0 +1,101 @@
+---
+title: "Vision & Audio"
+description: "Run LFM2.5-VL vision models and LFM2.5-Audio on llama.cpp: projector files, image and audio inputs, and the OpenAI-compatible multimodal API."
+---
+
+Multimodal LFMs run on llama.cpp through its `mtmd` library. A vision or audio GGUF comes in two parts: the language model (`LFM2.5-VL-1.6B-Q4_0.gguf`) and a projector / encoder file (`mmproj-*.gguf`). `llama-server`, `llama-cli`, and `llama-mtmd-cli` all load both; the same `mtmd` code is available in the iOS XCFramework and Android builds.
+
+## Vision (LFM2.5-VL)
+
+### Start the server
+
+```bash
+# -hf downloads the model and the matching mmproj automatically
+llama-server -hf LiquidAI/LFM2.5-VL-1.6B-GGUF:Q4_0 -c 4096 --port 8080 --jinja
+```
+
+Or with local files:
+
+```bash
+hf download LiquidAI/LFM2.5-VL-1.6B-GGUF LFM2.5-VL-1.6B-Q4_0.gguf mmproj-LFM2.5-VL-1.6b-Q8_0.gguf --local-dir .
+
+llama-server -m LFM2.5-VL-1.6B-Q4_0.gguf --mmproj mmproj-LFM2.5-VL-1.6b-Q8_0.gguf \
+ -c 4096 --port 8080 --jinja -ngl 99
+```
+
+Useful flags: `--image-max-tokens` caps the number of image tokens per picture (lower = faster, coarser); `--no-mmproj-offload` keeps the vision encoder on CPU when GPU memory is tight.
+
+### Send an image
+
+Images travel as standard OpenAI `image_url` content parts — a `data:` URI with base64 bytes or a public URL.
+
+```python
+import base64
+from openai import OpenAI
+
+client = OpenAI(base_url="http://localhost:8080/v1", api_key="not-needed")
+
+with open("photo.jpg", "rb") as f:
+ image_b64 = base64.b64encode(f.read()).decode()
+
+response = client.chat.completions.create(
+ model="lfm2.5-vl-1.6b",
+ messages=[{
+ "role": "user",
+ "content": [
+ {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}},
+ {"type": "text", "text": "Describe this image in two sentences."},
+ ],
+ }],
+ temperature=0.1,
+ max_tokens=256,
+ extra_body={"min_p": 0.15, "repeat_penalty": 1.05},
+)
+print(response.choices[0].message.content)
+```
+
+Multiple images in one message are supported; put each `image_url` part before the text that refers to it. Multi-turn works as for text — send the full history, and the image tokens stay in the prompt cache.
+
+Vision models use `temperature 0.1`, `min_p 0.15`, `repeat_penalty 1.05`. See [Vision Capabilities](/lfm/key-concepts/vision-capabilities) for prompting guidance and [LFM2.5-VL-1.6B](/lfm/models/lfm25-vl-1.6b) / [LFM2.5-VL-3B](/lfm/models/lfm25-vl-3b) for model details.
+
+### Command line
+
+```bash
+llama-mtmd-cli -m LFM2.5-VL-1.6B-Q4_0.gguf --mmproj mmproj-LFM2.5-VL-1.6b-Q8_0.gguf \
+ --image photo.jpg -p "What is in this image?" \
+ --temp 0.1 --min-p 0.15 --repeat-penalty 1.05
+```
+
+### In-process (mobile and embedded)
+
+The `mtmd` C API sits next to `llama.h`: load the projector with `mtmd_init_from_file()`, tokenize a prompt that contains image markers plus the image bitmaps with `mtmd_tokenize()`, evaluate the chunks with `mtmd_helper_eval_chunks()`, then sample text with the usual `llama_sampler_sample()` loop. [`tools/mtmd/README-dev.md`](https://github.com/ggml-org/llama.cpp/blob/master/tools/mtmd/README-dev.md) documents the API and [`tools/mtmd/mtmd-cli.cpp`](https://github.com/ggml-org/llama.cpp/blob/master/tools/mtmd/mtmd-cli.cpp) is a compact reference. On Android build with `-DLLAMA_BUILD_MTMD=ON`; the iOS XCFramework already includes it.
+
+Downscale images before passing them to the model — LFM2.5-VL handles native resolution, but a 12-megapixel camera frame costs far more image tokens than a 1024-pixel resize with no accuracy benefit for most tasks.
+
+## Audio (LFM2.5-Audio)
+
+LFM2.5-Audio adds a custom audio detokenizer for speech output, so it runs on llama.cpp through Liquid's dedicated audio runners rather than the generic `mtmd` path. The GGUF repository ships four files per quantization: the language model, the `mmproj-*` audio encoder, the `vocoder-*` decoder, and the `tokenizer-*` speaker file.
+
+```bash
+hf download LiquidAI/LFM2.5-Audio-1.5B-GGUF --include "*Q4_0.gguf" --local-dir ./LFM2.5-Audio-1.5B-GGUF
+export CKPT=./LFM2.5-Audio-1.5B-GGUF
+
+# Speech-to-text (ASR)
+./llama-liquid-audio-cli -m $CKPT/LFM2.5-Audio-1.5B-Q4_0.gguf \
+ -mm $CKPT/mmproj-LFM2.5-Audio-1.5B-Q4_0.gguf \
+ -mv $CKPT/vocoder-LFM2.5-Audio-1.5B-Q4_0.gguf \
+ --tts-speaker-file $CKPT/tokenizer-LFM2.5-Audio-1.5B-Q4_0.gguf \
+ -sys "Perform ASR." --audio input.wav
+
+# Server mode (ASR, TTS, and interleaved speech-in / speech-out over HTTP)
+./llama-liquid-audio-server -m $CKPT/LFM2.5-Audio-1.5B-Q4_0.gguf \
+ -mm $CKPT/mmproj-LFM2.5-Audio-1.5B-Q4_0.gguf \
+ -mv $CKPT/vocoder-LFM2.5-Audio-1.5B-Q4_0.gguf \
+ --tts-speaker-file $CKPT/tokenizer-LFM2.5-Audio-1.5B-Q4_0.gguf
+```
+
+The [LFM2.5-Audio-1.5B model page](/lfm/models/lfm25-audio-1.5b) has the TTS and interleaved-mode commands and the list of platforms the runners are built for (macOS arm64, Ubuntu x64/arm64, Android arm64). The [real-time transcription example](/examples/laptop-examples/audio-to-text-in-real-time) is a complete Python CLI that downloads the runner and drives it; the [Hand & Voice Racer](/examples/web/hand-voice-racer) and [Audio Browser Demo](/examples/web/audio-webgpu-demo) show the same model in the browser.
+
+
+Audio input is 16 kHz mono WAV. Resample and downmix on the client (`AVAudioConverter` on iOS, `AudioRecord` at 16 kHz on Android, `ffmpeg -ar 16000 -ac 1` on desktop) before sending it to the model.
+
diff --git a/deployment/on-device/llama-cpp/structured-output.mdx b/deployment/on-device/llama-cpp/structured-output.mdx
new file mode 100644
index 00000000..2656e42a
--- /dev/null
+++ b/deployment/on-device/llama-cpp/structured-output.mdx
@@ -0,0 +1,166 @@
+---
+title: "Structured Output"
+description: "Constrain LFM generation on llama.cpp to a JSON schema or GBNF grammar so output always parses."
+---
+
+llama.cpp enforces structure at decode time: tokens that would break the schema get zero probability, so the output is guaranteed to parse. You can supply a **JSON Schema** (converted to a grammar automatically) or a hand-written **GBNF grammar**. Both work in `llama-server`, the CLI tools, and the C API.
+
+## JSON schema with llama-server
+
+Pass an OpenAI-style `response_format`. `llama-server` converts the schema to a grammar for that request.
+
+```python
+import json
+from openai import OpenAI
+
+client = OpenAI(base_url="http://localhost:8080/v1", api_key="not-needed")
+
+recipe_schema = {
+ "type": "object",
+ "properties": {
+ "name": {"type": "string", "description": "Recipe title"},
+ "servings": {"type": "integer", "minimum": 1},
+ "ingredients": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "item": {"type": "string"},
+ "quantity": {"type": "string"},
+ },
+ "required": ["item", "quantity"],
+ },
+ },
+ "steps": {"type": "array", "items": {"type": "string"}},
+ },
+ "required": ["name", "servings", "ingredients", "steps"],
+}
+
+response = client.chat.completions.create(
+ model="lfm2.5-1.2b-instruct",
+ messages=[
+ {"role": "system", "content": "You write recipes as JSON with fields name, servings, ingredients (item, quantity), and steps."},
+ {"role": "user", "content": "A quick weeknight pasta for two."},
+ ],
+ response_format={"type": "json_schema", "json_schema": {"name": "recipe", "schema": recipe_schema}},
+ temperature=0.1,
+ max_tokens=512,
+ extra_body={"top_k": 50, "repeat_penalty": 1.05},
+)
+
+recipe = json.loads(response.choices[0].message.content)
+print(recipe["name"], len(recipe["steps"]))
+```
+
+`{"type": "json_object"}` (any valid JSON) is also accepted, and the non-OpenAI `/completion` endpoint takes the schema directly in a `json_schema` field.
+
+
+The grammar constrains *which tokens can be produced*; it does not tell the model *what* to produce. Describe the fields in the system prompt (as above) so the model fills them meaningfully instead of emitting the shortest string that satisfies the schema.
+
+
+Supported schema features include `object` / `array` / `string` / `number` / `integer` / `boolean` / `null`, `enum`, `const`, `required`, `additionalProperties`, `minItems` / `maxItems`, `minLength` / `maxLength`, `pattern`, `anyOf` / `oneOf`, `$ref` and `$defs`. Unsupported keywords are ignored rather than rejected, so validate the parsed object in your code as well.
+
+## GBNF grammars
+
+For non-JSON formats (a fixed set of labels, a date, a command line), write a small grammar in llama.cpp's [GBNF](https://github.com/ggml-org/llama.cpp/blob/master/grammars/README.md) syntax:
+
+```
+root ::= sentiment
+sentiment ::= "positive" | "neutral" | "negative"
+```
+
+Use it per request (`grammar` field on `/completion` or `/v1/chat/completions`) or globally with `--grammar-file` on `llama-server` / `llama-cli`:
+
+```bash
+curl http://localhost:8080/v1/chat/completions \
+ -H "Content-Type: application/json" \
+ -d '{
+ "messages": [{"role": "user", "content": "Classify: I love this phone."}],
+ "grammar": "root ::= \"positive\" | \"neutral\" | \"negative\"",
+ "temperature": 0.1, "top_k": 50, "repeat_penalty": 1.05
+ }'
+```
+
+To see the grammar llama.cpp generates for a schema, or to ship a pre-converted grammar with your app:
+
+```bash
+python llama.cpp/examples/json_schema_to_grammar.py schema.json > schema.gbnf
+```
+
+## In-process bindings
+
+
+
+ Add a grammar sampler to the chain before the final `dist` sampler. Convert JSON schemas ahead of time with `json_schema_to_grammar.py`, or at runtime with `json_schema_to_grammar()` from the `common` library.
+
+ ```c
+ const char * gbnf = /* contents of schema.gbnf */;
+ llama_sampler_chain_add(smpl, llama_sampler_init_grammar(vocab, gbnf, "root"));
+ llama_sampler_chain_add(smpl, llama_sampler_init_top_k(50));
+ llama_sampler_chain_add(smpl, llama_sampler_init_penalties(llama_vocab_n_tokens(vocab), 64, 1.05f, 0.0f, 0.0f));
+ llama_sampler_chain_add(smpl, llama_sampler_init_temp(0.1f));
+ llama_sampler_chain_add(smpl, llama_sampler_init_dist(LLAMA_DEFAULT_SEED));
+ ```
+
+ The grammar sampler is stateful: call `llama_sampler_reset(smpl)` (or rebuild the chain) before each new generation.
+
+
+ ```python
+ from llama_cpp import Llama
+
+ llm = Llama.from_pretrained(
+ repo_id="LiquidAI/LFM2.5-1.2B-Instruct-GGUF",
+ filename="*Q4_K_M.gguf",
+ n_ctx=4096,
+ )
+
+ out = llm.create_chat_completion(
+ messages=[
+ {"role": "system", "content": "Extract the person's name and age as JSON."},
+ {"role": "user", "content": "Ada Lovelace was 36 when she died in 1852."},
+ ],
+ response_format={
+ "type": "json_object",
+ "schema": {
+ "type": "object",
+ "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
+ "required": ["name", "age"],
+ },
+ },
+ temperature=0.1, top_k=50, repeat_penalty=1.05, max_tokens=128,
+ )
+ print(out["choices"][0]["message"]["content"]) # {"name": "Ada Lovelace", "age": 36}
+ ```
+
+
+ ```typescript
+ import { getLlama, LlamaChatSession, resolveModelFile } from "node-llama-cpp";
+
+ const llama = await getLlama();
+ const modelPath = await resolveModelFile(
+ "hf:LiquidAI/LFM2.5-1.2B-Instruct-GGUF/LFM2.5-1.2B-Instruct-Q4_K_M.gguf", "./models");
+ const model = await llama.loadModel({ modelPath });
+ const context = await model.createContext();
+ const session = new LlamaChatSession({ contextSequence: context.getSequence() });
+
+ const grammar = await llama.createGrammarForJsonSchema({
+ type: "object",
+ properties: { name: { type: "string" }, age: { type: "integer" } },
+ required: ["name", "age"],
+ });
+
+ const text = await session.prompt("Ada Lovelace was 36 when she died in 1852. Extract name and age.", {
+ grammar, temperature: 0.1, topK: 50, repeatPenalty: { penalty: 1.05 },
+ });
+ const parsed = grammar.parse(text); // typed object
+ ```
+
+
+
+## Best practices
+
+- **Keep schemas small.** Every optional field and nested object enlarges the grammar and the model's decision space. Split large extractions into several focused calls.
+- **Describe fields in the prompt.** The schema is invisible to the model; field names and a one-line description per field in the system prompt are what steer content.
+- **Use low temperature.** `0.1` (the LFM2.5 default) is right for structured output.
+- **Validate anyway.** Grammar guarantees syntax, not semantics — check ranges, enums, and referential consistency in application code and retry on failure.
+- **Avoid open-ended strings at the end.** A final unbounded `string` field can run until `max_tokens`; set `maxLength` or put bounded fields last.
diff --git a/deployment/on-device/sdk/advanced-features.mdx b/deployment/on-device/sdk/advanced-features.mdx
index 88baa9de..73d10a3c 100644
--- a/deployment/on-device/sdk/advanced-features.mdx
+++ b/deployment/on-device/sdk/advanced-features.mdx
@@ -1,8 +1,13 @@
---
title: "Advanced Features"
description: "GenerationOptions, JSONSchemaGenerator, function-calling type references — same surface everywhere."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
This page consolidates the lower-level reference symbols used by [Constrained Generation](./constrained-generation) and [Function Calling](./function-calling). Most apps don't touch these directly — the high-level pages cover the usual flows. Reach here when you need to inspect schemas, build options programmatically, or wire a custom parser.
## `GenerationOptions`
diff --git a/deployment/on-device/sdk/ai-agent-usage-guide.mdx b/deployment/on-device/sdk/ai-agent-usage-guide.mdx
index bd117c2b..a2060d00 100644
--- a/deployment/on-device/sdk/ai-agent-usage-guide.mdx
+++ b/deployment/on-device/sdk/ai-agent-usage-guide.mdx
@@ -1,8 +1,13 @@
---
title: "AI Agent Usage Guide"
description: "End-to-end recipes for building AI agents with the LEAP SDK — same patterns across iOS, macOS, Android, JVM, and native."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
This guide walks through the patterns for building a real AI agent — multi-turn conversation, function calling with tool dispatch, multimodal inputs, and a complete view-model wiring. The cross-platform pages cover individual APIs in depth — start here for the full picture, then drill into the dedicated references when you need details.
## Architecture
diff --git a/deployment/on-device/sdk/cloud-ai-comparison.mdx b/deployment/on-device/sdk/cloud-ai-comparison.mdx
index 06be32e4..5684f823 100644
--- a/deployment/on-device/sdk/cloud-ai-comparison.mdx
+++ b/deployment/on-device/sdk/cloud-ai-comparison.mdx
@@ -1,8 +1,13 @@
---
title: "Cloud AI Comparison"
description: "Mapping LEAP SDK concepts to cloud chat-completion APIs like OpenAI."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
If you've used a cloud chat-completion API (OpenAI, Anthropic, etc.), most of LEAP's shape will be familiar — async streaming, role-tagged messages, JSON-serializable history. The biggest difference: you load the model explicitly, locally, before generation, instead of pointing a client at a remote endpoint.
This page maps the OpenAI Python client's flow onto the LEAP SDK across Swift, Kotlin (Android), and Kotlin (JVM / native). For OpenAI compatibility on the client side, also see [OpenAI-Compatible Client](./openai-client).
diff --git a/deployment/on-device/sdk/constrained-generation.mdx b/deployment/on-device/sdk/constrained-generation.mdx
index 11573bf9..a39fa3fe 100644
--- a/deployment/on-device/sdk/constrained-generation.mdx
+++ b/deployment/on-device/sdk/constrained-generation.mdx
@@ -1,8 +1,13 @@
---
title: "Constrained Generation"
description: "Generate structured JSON output with compile-time validation — same approach on every platform."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Constrained generation forces the model to emit JSON matching a schema. Use the language's native facility — Swift macros (`@Generatable` / `@Guide`) or Kotlin annotations (`@Generatable` / `@Guide`) — to define the structure, then set it on `GenerationOptions`. The schema is computed at compile time (Swift) or built from the `kotlinx.serialization` descriptor at runtime (Kotlin), and the model's output decodes directly into your type.
## Define the structured type
diff --git a/deployment/on-device/sdk/conversation-generation.mdx b/deployment/on-device/sdk/conversation-generation.mdx
index e9815a26..aac8ad96 100644
--- a/deployment/on-device/sdk/conversation-generation.mdx
+++ b/deployment/on-device/sdk/conversation-generation.mdx
@@ -1,8 +1,13 @@
---
title: "Conversation & Generation"
description: "Reference for ModelRunner, Conversation, MessageResponse, and GenerationOptions — same API on every platform."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
All functions documented on this page are safe to call from the main/UI thread; callbacks run on the main thread unless explicitly noted. The API surface is identical across iOS, macOS, Android, JVM, and Kotlin/Native — only the language and a handful of platform conventions differ.
diff --git a/deployment/on-device/sdk/desktop-platforms.mdx b/deployment/on-device/sdk/desktop-platforms.mdx
index 26ca1c65..01e96219 100644
--- a/deployment/on-device/sdk/desktop-platforms.mdx
+++ b/deployment/on-device/sdk/desktop-platforms.mdx
@@ -1,8 +1,13 @@
---
title: "Desktop & Native Platforms"
description: "Run the LEAP SDK on JVM desktop, native Linux, native Windows, and macOS — same API as Android and iOS."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
The LEAP SDK is a Kotlin Multiplatform library. The same conversation, model-loading, and generation APIs you use on Android and iOS run unchanged on JVM desktop and Kotlin/Native targets. This page covers installation and per-platform notes for everything outside the mobile guides.
diff --git a/deployment/on-device/sdk/function-calling.mdx b/deployment/on-device/sdk/function-calling.mdx
index 1bec418e..ba5e5d2b 100644
--- a/deployment/on-device/sdk/function-calling.mdx
+++ b/deployment/on-device/sdk/function-calling.mdx
@@ -1,8 +1,13 @@
---
title: "Function Calling"
description: "Tool use with LeapFunction — same API on every platform, with Hermes and Pythonic parsers."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Function calling lets the model invoke predefined functions provided by your app — query an API, run a calculation, fetch external state. Register `LeapFunction` definitions on the `Conversation`, run generation as usual, and the model's tool-call tokens come back as `MessageResponse.functionCalls`.
diff --git a/deployment/on-device/sdk/messages-content.mdx b/deployment/on-device/sdk/messages-content.mdx
index f30edb60..34547e07 100644
--- a/deployment/on-device/sdk/messages-content.mdx
+++ b/deployment/on-device/sdk/messages-content.mdx
@@ -1,8 +1,13 @@
---
title: "Messages & Content"
description: "ChatMessage, ChatMessageContent, audio format requirements — same shape on every platform."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
`ChatMessage` and `ChatMessageContent` mirror the OpenAI chat-completions message schema. Both are declared once in `commonMain` (`data class ChatMessage`, `sealed class ChatMessageContent`) and Kotlin/Native + SKIE bridge the Kotlin types into Swift — there are no separate "native" Swift declarations.
## `ChatMessage`
diff --git a/deployment/on-device/sdk/model-loading.mdx b/deployment/on-device/sdk/model-loading.mdx
index e33ee29a..956f3786 100644
--- a/deployment/on-device/sdk/model-loading.mdx
+++ b/deployment/on-device/sdk/model-loading.mdx
@@ -1,8 +1,13 @@
---
title: "Model Loading"
description: "Reference for ModelDownloader, LeapDownloader, loadModel, loadSimpleModel, and KV cache reuse."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
The LEAP SDK ships two downloader classes built on the same pipeline. They differ by what platform integration they add:
| Platform | Class | What it does |
diff --git a/deployment/on-device/sdk/openai-client.mdx b/deployment/on-device/sdk/openai-client.mdx
index b63416b2..e50be65f 100644
--- a/deployment/on-device/sdk/openai-client.mdx
+++ b/deployment/on-device/sdk/openai-client.mdx
@@ -1,8 +1,13 @@
---
title: "OpenAI-Compatible Client"
description: "Lightweight client for OpenAI-compatible chat completions APIs — ideal for hybrid on-device + cloud routing."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
`LeapOpenAIClient` / `leap-openai-client` (introduced in v0.10.0) is a small, dependency-light client for any OpenAI-compatible chat-completions endpoint — OpenAI itself, OpenRouter, vLLM, llama-server, or your own proxy. It ships in the same SDK release as `LeapSDK`, so you can route requests between an on-device LFM and a cloud model from a single app.
## When to use it
diff --git a/deployment/on-device/sdk/overview.mdx b/deployment/on-device/sdk/overview.mdx
index 8393ad2a..fdbc29a4 100644
--- a/deployment/on-device/sdk/overview.mdx
+++ b/deployment/on-device/sdk/overview.mdx
@@ -1,40 +1,41 @@
---
-title: "Overview"
-sidebarTitle: "LEAP SDK"
+title: "LEAP SDK (archived)"
+description: "The LEAP SDK is deprecated. This archived reference is kept for teams still shipping it; new projects should use llama.cpp directly."
+noindex: true
---
-The **Leap SDK** is Liquid AI's official on-device inference SDK and the **only SDK with first-class support for [Liquid Foundation Models](https://www.liquid.ai/blog/liquid-foundation-models-our-first-series-of-generative-ai-models) (LFMs)** — LFM2, LFM2.5 (text, thinking, JP, VL), and LFM2.5-Audio. "First-class" means every published Liquid checkpoint is supported, validated, and shipped through this SDK on day-one — the same team that trains the models ships the engine, sampler defaults, chat templates, and tool-call parsers that run them. There is no separate adapter layer, no community port, no upstream-rebase lag.
-
-It's also a Kotlin Multiplatform library: the same `ModelRunner` / `Conversation` / `MessageResponse` API runs on iOS, macOS, Android, JVM desktop, Linux native, Windows native, and (preview) wasmJs. The Swift surface is generated through Kotlin/Native + SKIE and ships as XCFrameworks; the Android/JVM surface ships as Maven Central artifacts. Both call shapes are identical — only the language and packaging differ.
-
-
- Jump to the **Quick Start** — install via SPM or Gradle, load a model, stream a response.
-
-
-## What "first-class support for Liquid models" gets you
-
-- **Day-one model coverage.** New LFM checkpoints land in the SDK release that announces them — no waiting for a generic runtime to catch up to a new architecture, no manual quant conversion, no template-mismatch debugging. The [LEAP Model Library](https://leap.liquid.ai/models) is the canonical distribution path and the SDK pulls directly from it.
-- **Per-checkpoint validated defaults.** The sampling parameters baked into each model's bundle manifest (`sampling_parameters` under `generation_time_parameters` in each `.json` on [LiquidAI/LeapBundles](https://huggingface.co/LiquidAI/LeapBundles)) are the values the training team validated for that exact checkpoint. The SDK applies them automatically — no `temperature=0.7` placeholder retuning, no token-stream artifacts from the wrong `min_p` / `repetition_penalty`.
-- **LFM-native special tokens and chat templates.** The shipped engine knows how to filter LFM control tokens before they reach your stream, applies the right chat template per checkpoint, and parses LFM's hermes and pythonic function-call dialects out of the box. Generic SDKs treat these as opaque text and surface raw tokens; Leap surfaces typed `MessageResponse.FunctionCalls` with parsed argument maps.
-- **Multimodal LFMs in one API.** Vision (LFM2-VL family) and audio (LFM2.5-Audio) plug into the same `ChatMessage` / `ChatMessageContent` types you already use for text. Image inputs travel as JPEG bytes; audio travels as WAV blobs (or raw float32 PCM on Kotlin via `AudioPcmF32`). Output `MessageResponse.AudioSample` streams float32 PCM frames for audio-out checkpoints. No separate runtime per modality.
-- **Constrained generation, end-to-end.** Kotlin annotations (`@Generatable` / `@Guide` on `@Serializable` data classes) and Swift macros (`@Generatable` / `@Guide` synthesizing `jsonSchema()` at compile time) produce JSON Schemas the engine enforces at decode time. The model's output is guaranteed to parse into your type.
-- **One-call model fetching from the LEAP Model Library.** `LeapModelDownloader.loadModel(modelName:, quantizationType:)` resolves a manifest, downloads the right GGUF + matching `mmproj`/audio-decoder companion files for the checkpoint, caches them on disk, and hands back a `ModelRunner` — one call, no manual path wiring, no companion-file detection. Background-safe on iOS (`URLSessionConfiguration.background(withIdentifier:)`), WorkManager-backed on Android (survives app restarts).
-
-## Other features
-
-- **On-device by default.** No cloud round-trip, no per-token cost, full privacy, full offline operation.
-- **KV cache reuse for fast multi-turn.** Bounded-LRU disk + memory `CacheOptions` skip the prefill step for shared prompt prefixes — TTFT on a long system prompt or RAG preamble drops from seconds to under a hundred milliseconds on cache hits. Disabled by default; opt in with `LiquidCacheOptions.enabled(path:)` / `ModelLoadingOptions.cacheOptions(path = ...)`.
-- **Memory-mapped weight loading.** `use_mmap=true` is the default since v0.10.4. Model weights are file-backed, not anonymous RSS — iOS jetsam and Android LMK score the app much lower under memory pressure, cold load returns as soon as the file is mapped, and warm reloads stream from the kernel page cache.
-- **Hybrid on-device + cloud routing.** `leap-openai-client` ships in the same release as an opt-in OpenAI-compatible chat-completions client (OpenAI, OpenRouter, vLLM, llama-server). One binary, two code paths — route small/fast prompts on-device, fall back to a cloud model for hard ones, share the same `ChatMessage` types.
-- **Drop-in voice assistant UI.** `leap-ui` ships a Compose Multiplatform voice widget — animated orb, mic button, status label, state machine — that pairs with `VoiceConversation` to wire LFM2.5-Audio into a working voice experience without writing the recording-and-playback plumbing yourself.
-
-## Where to go next
-
-- [Quick Start](/deployment/on-device/sdk/quick-start) — install and run your first generation.
-- [Model Loading](/deployment/on-device/sdk/model-loading) — manifest-based downloads, sideloaded GGUFs, `ModelLoadingOptions` reference, KV cache configuration.
-- [Conversation & Generation](/deployment/on-device/sdk/conversation-generation) — the streaming generation API.
-- [Constrained Generation](/deployment/on-device/sdk/constrained-generation) — `@Generatable` types and JSON-schema-enforced output.
-- [Function Calling](/deployment/on-device/sdk/function-calling) — tool definitions, function-call parsing, hermes / pythonic dialects.
-- [Voice Assistant Widget](/deployment/on-device/sdk/voice-assistant) — drop-in Compose Multiplatform voice UI.
-- [OpenAI-Compatible Client](/deployment/on-device/sdk/openai-client) — hybrid on-device + cloud routing.
-- [Migrating from 0.9.x?](/deployment/on-device/leap-sdk-changelog#0-9-x-0-10-x-kotlin-multiplatform-unification) — the unification story and drop-in replacements for legacy `Leap.load(...)` / `LiquidEngine(...)` call sites.
+
+The **LEAP SDK is deprecated** and no longer receives new releases. It was a Kotlin Multiplatform wrapper around llama.cpp, and everything it provided is available from llama.cpp directly. New projects should follow the [Build with llama.cpp](/deployment/on-device/llama-cpp/mobile) guides; existing users can find a concept-by-concept mapping in [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
+Published LEAP SDK artifacts remain available (Swift Package Manager via [`Liquid4All/leap-sdk`](https://github.com/Liquid4All/leap-sdk), Maven Central under `ai.liquid.leap:*`), but they are frozen at their last release and are not updated for new LFM checkpoints. Sampling defaults, chat templates, and tool-call parsing for current models are maintained upstream in llama.cpp.
+
+## Archived reference
+
+These pages document the final LEAP SDK release (v0.10.x) and are no longer maintained.
+
+- [Quick Start](/deployment/on-device/sdk/quick-start)
+- [Model Loading](/deployment/on-device/sdk/model-loading)
+- [Conversation & Generation](/deployment/on-device/sdk/conversation-generation)
+- [Messages & Content](/deployment/on-device/sdk/messages-content)
+- [Function Calling](/deployment/on-device/sdk/function-calling)
+- [Constrained Generation](/deployment/on-device/sdk/constrained-generation)
+- [Advanced Features](/deployment/on-device/sdk/advanced-features)
+- [Utilities](/deployment/on-device/sdk/utilities)
+- [Voice Assistant Widget](/deployment/on-device/sdk/voice-assistant)
+- [OpenAI-Compatible Client](/deployment/on-device/sdk/openai-client)
+- [Cloud AI Comparison](/deployment/on-device/sdk/cloud-ai-comparison)
+- [Desktop & Native Platforms](/deployment/on-device/sdk/desktop-platforms)
+- [AI Agent Usage Guide](/deployment/on-device/sdk/ai-agent-usage-guide)
+- [Changelog](/deployment/on-device/leap-sdk-changelog)
+
+## Where to go instead
+
+
+
+ Every LEAP SDK concept mapped to its llama.cpp equivalent.
+
+
+ Embed llama.cpp in a mobile app and run LFM GGUF models on-device.
+
+
diff --git a/deployment/on-device/sdk/quick-start.mdx b/deployment/on-device/sdk/quick-start.mdx
index 348c902b..60640ed1 100644
--- a/deployment/on-device/sdk/quick-start.mdx
+++ b/deployment/on-device/sdk/quick-start.mdx
@@ -1,8 +1,13 @@
---
title: "Quick Start"
description: "Install the LEAP SDK on iOS, macOS, Android, JVM, Linux, or Windows — same API everywhere."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Latest version: `v0.10.7`
The Leap SDK is a Kotlin Multiplatform library: the same `ModelRunner` / `Conversation` / `MessageResponse` API runs on every supported target. The code differs only in **language** (Swift vs. Kotlin) and **packaging** (SPM, Gradle, or Kotlin/Native plugin) — the call shapes are identical. For background on what the SDK is and what first-class LFM support means in practice, see the [Overview](/deployment/on-device/sdk/overview).
diff --git a/deployment/on-device/sdk/utilities.mdx b/deployment/on-device/sdk/utilities.mdx
index e57ad7c1..d3352828 100644
--- a/deployment/on-device/sdk/utilities.mdx
+++ b/deployment/on-device/sdk/utilities.mdx
@@ -1,8 +1,13 @@
---
title: "Utilities"
description: "Error handling, serialization, Android-specific downloader internals, and a putting-it-together example."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
This page covers error types, serialization helpers, and a few platform-specific entry points that don't fit in the main reference pages.
## Errors
diff --git a/deployment/on-device/sdk/voice-assistant.mdx b/deployment/on-device/sdk/voice-assistant.mdx
index 14f18848..bec83e02 100644
--- a/deployment/on-device/sdk/voice-assistant.mdx
+++ b/deployment/on-device/sdk/voice-assistant.mdx
@@ -1,8 +1,13 @@
---
title: "Voice Assistant Widget"
description: "Drop-in Compose Multiplatform voice UI — runs on iOS, macOS, Android, and JVM Desktop."
+noindex: true
---
+
+The LEAP SDK is deprecated and this page is no longer maintained. Build on llama.cpp directly instead — see [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
The `leap-ui` module (introduced in v0.10.0) ships a ready-to-use voice assistant widget — an animated orb, mic button, and status label — backed by a state machine that handles recording, generation, and audio playback. Wire it to a model and it handles the rest.
`leap-ui` is a Compose Multiplatform module, so the same widget runs on:
diff --git a/deployment/tools/model-bundling/quick-start.mdx b/deployment/tools/model-bundling/quick-start.mdx
index 47101561..49e29a28 100644
--- a/deployment/tools/model-bundling/quick-start.mdx
+++ b/deployment/tools/model-bundling/quick-start.mdx
@@ -3,6 +3,10 @@ title: "Quick Start"
description: "The Bundling Service helps users create and manage model bundles for Liquid Edge AI Platform (LEAP). Currently users interact with it through a command-line interface (CLI)."
---
+
+ The LEAP Model Bundling Service is deprecated and no longer maintained. For new deployments, download GGUF files from [Hugging Face](https://huggingface.co/LiquidAI) and run them with [llama.cpp](/deployment/on-device/llama-cpp).
+
+
The CLI supports two main workflows:
- **GGUF Model Download**: Download pre-built models from the LEAP Model Library (no authentication required)
diff --git a/docs.json b/docs.json
index 76c73fbe..9b9d7aee 100644
--- a/docs.json
+++ b/docs.json
@@ -92,8 +92,8 @@
"group": "Edge Inference",
"icon": "mobile",
"pages": [
- "deployment/on-device/sdk/overview",
"deployment/on-device/llama-cpp",
+ "deployment/on-device/llama-cpp/mobile",
"deployment/on-device/lm-studio",
"deployment/on-device/mlx",
"deployment/on-device/onnx",
@@ -142,47 +142,6 @@
}
]
},
- {
- "tab": "Leap SDK",
- "groups": [
- {
- "group": "Leap SDK",
- "icon": "rocket",
- "pages": [
- "deployment/on-device/sdk/overview",
- "deployment/on-device/sdk/quick-start",
- "deployment/on-device/sdk/ai-agent-usage-guide",
- "deployment/on-device/sdk/model-loading",
- "deployment/on-device/sdk/conversation-generation",
- "deployment/on-device/sdk/messages-content",
- "deployment/on-device/sdk/function-calling",
- "deployment/on-device/sdk/constrained-generation",
- "deployment/on-device/sdk/advanced-features",
- "deployment/on-device/sdk/utilities",
- "deployment/on-device/sdk/voice-assistant",
- "deployment/on-device/sdk/openai-client",
- "deployment/on-device/sdk/cloud-ai-comparison",
- "deployment/on-device/sdk/desktop-platforms",
- "deployment/on-device/leap-sdk-changelog"
- ]
- },
- {
- "group": "Model Bundling Services",
- "icon": "box",
- "pages": [
- "deployment/tools/model-bundling/quick-start",
- "deployment/tools/model-bundling/authentication",
- "deployment/tools/model-bundling/configuration",
- "deployment/tools/model-bundling/bundle-creation",
- "deployment/tools/model-bundling/bundle-management",
- "deployment/tools/model-bundling/download",
- "deployment/tools/model-bundling/reference",
- "deployment/tools/model-bundling/data-privacy",
- "deployment/tools/model-bundling/changelog"
- ]
- }
- ]
- },
{
"tab": "Examples",
"groups": [
diff --git a/examples/android/leap-koog-agent.mdx b/examples/android/leap-koog-agent.mdx
index 4049c64d..4cd375be 100644
--- a/examples/android/leap-koog-agent.mdx
+++ b/examples/android/leap-koog-agent.mdx
@@ -2,6 +2,10 @@
title: "Build AI Agents with Koog Framework on Android"
---
+
+This example uses the LEAP SDK, which is **deprecated**. It remains a useful architectural reference, but for new Android apps embed llama.cpp directly — see [iOS & Android](/deployment/on-device/llama-cpp/mobile) and [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Browse the complete example on GitHub
diff --git a/examples/android/recipe-generator-constrained-output.mdx b/examples/android/recipe-generator-constrained-output.mdx
index 67efce03..160e1899 100644
--- a/examples/android/recipe-generator-constrained-output.mdx
+++ b/examples/android/recipe-generator-constrained-output.mdx
@@ -2,6 +2,10 @@
title: "Generate Structured Recipes with Constrained Output"
---
+
+This example uses the LEAP SDK, which is **deprecated**. It remains a useful architectural reference, but for new Android apps embed llama.cpp directly — see [iOS & Android](/deployment/on-device/llama-cpp/mobile) and [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Browse the complete example on GitHub
diff --git a/examples/android/slogan-generator.mdx b/examples/android/slogan-generator.mdx
index 0bc295da..cd4364a9 100644
--- a/examples/android/slogan-generator.mdx
+++ b/examples/android/slogan-generator.mdx
@@ -2,6 +2,10 @@
title: "Product Slogan Generator with LeapSDK"
---
+
+This example uses the LEAP SDK, which is **deprecated**. It remains a useful architectural reference, but for new Android apps embed llama.cpp directly — see [iOS & Android](/deployment/on-device/llama-cpp/mobile) and [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Browse the complete example on GitHub
diff --git a/examples/android/vision-language-model-example.mdx b/examples/android/vision-language-model-example.mdx
index 3b8f7586..896069bf 100644
--- a/examples/android/vision-language-model-example.mdx
+++ b/examples/android/vision-language-model-example.mdx
@@ -2,6 +2,10 @@
title: "Image Understanding with Vision Language Models"
---
+
+This example uses the LEAP SDK, which is **deprecated**. It remains a useful architectural reference, but for new Android apps embed llama.cpp directly — see [iOS & Android](/deployment/on-device/llama-cpp/mobile) and [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Browse the complete example on GitHub
diff --git a/examples/android/web-content-summarizer.mdx b/examples/android/web-content-summarizer.mdx
index ab85ae3f..99bcfe23 100644
--- a/examples/android/web-content-summarizer.mdx
+++ b/examples/android/web-content-summarizer.mdx
@@ -2,6 +2,10 @@
title: "Web Content Summarizer for Android"
---
+
+This example uses the LEAP SDK, which is **deprecated**. It remains a useful architectural reference, but for new Android apps embed llama.cpp directly — see [iOS & Android](/deployment/on-device/llama-cpp/mobile) and [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk).
+
+
Browse the complete example on GitHub
diff --git a/examples/index.mdx b/examples/index.mdx
index fc5d6cec..f9d4ee69 100644
--- a/examples/index.mdx
+++ b/examples/index.mdx
@@ -38,6 +38,10 @@ title: "Examples Library"
## Android
+
+These Android examples were built with the LEAP SDK, which is now deprecated. For new apps, embed llama.cpp directly — see [iOS & Android](/deployment/on-device/llama-cpp/mobile).
+
+
@@ -49,7 +53,7 @@ title: "Examples Library"
- Generate recipes with guaranteed JSON structure using constrained generation. Demonstrates automatic model downloading with LeapSDK.
+ Generate recipes with guaranteed JSON structure using constrained generation. Demonstrates automatic model downloading.
diff --git a/guides/hardware-evaluation.mdx b/guides/hardware-evaluation.mdx
index 9c77fb1b..a068adb4 100644
--- a/guides/hardware-evaluation.mdx
+++ b/guides/hardware-evaluation.mdx
@@ -29,7 +29,7 @@ The LFM2 and LFM2.5 architecture interleaves short convolutions with grouped-que
| Ollama | [Ollama](/deployment/on-device/ollama) | Local development |
| MLX | [MLX](/deployment/on-device/mlx) | Apple Silicon |
| ONNX | [ONNX](/deployment/on-device/onnx) | NPUs and accelerator toolchains |
-| LEAP SDK | [Quick Start](/deployment/on-device/sdk/quick-start) | iOS and Android apps |
+| llama.cpp (embedded) | [iOS & Android](/deployment/on-device/llama-cpp/mobile) | iOS and Android apps |
For most silicon evaluations, **llama.cpp with GGUF** or **ONNX** is the fastest path to numbers on your target.
diff --git a/guides/migration-guide.mdx b/guides/migration-guide.mdx
index 579faca2..d9711a1a 100644
--- a/guides/migration-guide.mdx
+++ b/guides/migration-guide.mdx
@@ -36,7 +36,7 @@ Across runtimes, avoid carrying over hand-written Qwen, Llama, or Gemma prompt t
For GPU inference, see [Transformers](/deployment/gpu-inference/transformers), [vLLM](/deployment/gpu-inference/vllm), or [SGLang](/deployment/gpu-inference/sglang).
-For edge and on-device inference, see [llama.cpp](/deployment/on-device/llama-cpp), [Ollama](/deployment/on-device/ollama), [Atomic Chat](/deployment/on-device/atomic-chat), [LM Studio](/deployment/on-device/lm-studio), [MLX](/deployment/on-device/mlx), [ONNX](/deployment/on-device/onnx), or the [LEAP SDK](/deployment/on-device/sdk/quick-start).
+For edge and on-device inference, see [llama.cpp](/deployment/on-device/llama-cpp), [Ollama](/deployment/on-device/ollama), [Atomic Chat](/deployment/on-device/atomic-chat), [LM Studio](/deployment/on-device/lm-studio), [MLX](/deployment/on-device/mlx), or [ONNX](/deployment/on-device/onnx). To embed a model in a mobile or desktop app, see [Build with llama.cpp](/deployment/on-device/llama-cpp/mobile).
## Chat Template
diff --git a/lfm/help/deprecations.mdx b/lfm/help/deprecations.mdx
index 7f5b4442..afbb0280 100644
--- a/lfm/help/deprecations.mdx
+++ b/lfm/help/deprecations.mdx
@@ -131,6 +131,15 @@ Deprecated models remain available for download on Hugging Face, but they are no
+## Deprecated SDKs
+
+| Deprecated | Recommended replacement | Migration guide |
+|---|---|---|
+| LEAP SDK (iOS, Android, JVM, Kotlin/Native) | [llama.cpp](/deployment/on-device/llama-cpp) used directly — see [Build with llama.cpp](/deployment/on-device/llama-cpp/mobile) | [Migrating from LEAP SDK](/deployment/on-device/llama-cpp/migrating-from-leap-sdk) |
+| LEAP Model Bundling Service / `leap-bundle` | Download GGUF files from [Hugging Face](https://huggingface.co/LiquidAI) and run them with [llama.cpp](/deployment/on-device/llama-cpp) | [Build with llama.cpp](/deployment/on-device/llama-cpp) |
+
+The LEAP SDK was a wrapper around llama.cpp. Published artifacts remain available but receive no further updates; the [archived reference](/deployment/on-device/sdk/overview) stays online.
+
Looking for a currently supported model? Browse the full [model library](/lfm/models/complete-library).
diff --git a/lfm/help/faqs.mdx b/lfm/help/faqs.mdx
index 31c635f2..294bef06 100644
--- a/lfm/help/faqs.mdx
+++ b/lfm/help/faqs.mdx
@@ -16,11 +16,10 @@ Most LFM models support a 32K token context length for extended conversations an
LFM models are compatible with:
- [Transformers](/deployment/gpu-inference/transformers) - For research and development
-- [llama.cpp](/deployment/on-device/llama-cpp) - For efficient CPU inference
+- [llama.cpp](/deployment/on-device/llama-cpp) - For efficient CPU inference, including [iOS and Android apps](/deployment/on-device/llama-cpp/mobile)
- [vLLM](/deployment/gpu-inference/vllm) - For high-throughput production serving
- [MLX](/deployment/on-device/mlx) - For Apple Silicon optimization
- [Ollama](/deployment/on-device/ollama) - For easy local deployment
-- [LEAP](/deployment/on-device/sdk/quick-start) - For edge and mobile deployment
## Model Selection
@@ -49,7 +48,7 @@ LFM2.5 models are updated versions with improved training that deliver higher pe
## Deployment
-Yes! Use the [LEAP SDK](/deployment/on-device/sdk/quick-start) to deploy models on iOS and Android devices. LEAP provides optimized inference for edge deployment with support for quantized models.
+Yes! llama.cpp runs natively on iOS and Android with quantized GGUF models. See [iOS & Android](/deployment/on-device/llama-cpp/mobile) for embedding it in an app, and [Vision & Audio](/deployment/on-device/llama-cpp/multimodal) for multimodal models.
diff --git a/lfm/models/audio-models.mdx b/lfm/models/audio-models.mdx
index b637a920..0038fa40 100644
--- a/lfm/models/audio-models.mdx
+++ b/lfm/models/audio-models.mdx
@@ -82,5 +82,4 @@ Explore practical implementations using audio models:
- [Liquid Playground](https://playground.liquid.ai/chat?model=cmk0wefde000204jp2knb2qr8)
- [HuggingFace Collections](https://huggingface.co/LiquidAI/collections)
- [OpenRouter API](https://openrouter.ai/liquid)
- - [LEAP Model Library](https://leap.liquid.ai/models)
diff --git a/lfm/models/complete-library.mdx b/lfm/models/complete-library.mdx
index 19dbc004..a21407a6 100644
--- a/lfm/models/complete-library.mdx
+++ b/lfm/models/complete-library.mdx
@@ -8,7 +8,7 @@ description: "Liquid Foundation Models (LFMs) are a new class of multimodal arch
All of our models share the following capabilities:
- 32K token context length for extended conversations and document processing (128K for LFM2.5-8B-A1B)
-- Designed for fast inference with [Transformers](/deployment/gpu-inference/transformers), [llama.cpp](/deployment/on-device/llama-cpp), [vLLM](/deployment/gpu-inference/vllm), [SGLang](/deployment/gpu-inference/sglang), [MLX](/deployment/on-device/mlx), [Ollama](/deployment/on-device/ollama), [Atomic Chat](/deployment/on-device/atomic-chat), and [LEAP](/deployment/on-device/sdk/quick-start)
+- Designed for fast inference with [Transformers](/deployment/gpu-inference/transformers), [llama.cpp](/deployment/on-device/llama-cpp), [vLLM](/deployment/gpu-inference/vllm), [SGLang](/deployment/gpu-inference/sglang), [MLX](/deployment/on-device/mlx), [Ollama](/deployment/on-device/ollama), and [Atomic Chat](/deployment/on-device/atomic-chat)
- Trainable via SFT, DPO, VLM, and GRPO workflows with [LEAP Finetune](/lfm/fine-tuning/leap-finetune), [TRL](/lfm/fine-tuning/trl), and [Unsloth](/lfm/fine-tuning/unsloth)
@@ -53,7 +53,7 @@ Start with the model family that matches your input and output shape, then choos