<!-- llms-explorer concept facts · https://llms-explorer.com/tree/llama-cpp-jinja-runtime-minja-replacement-tojson/ · pack 2026-10-05 · ~1345 tokens -->

# llama.cpp Jinja runtime (minja replacement) tojson and filter semantics

> The README says the engine "was introduced in PR#18462", lives in `common/jinja`, was originally inspired by huggingface.js's jinja package, and avoids C++ operator overloading.

Parent: [Mac local LLMs: llama.cpp internals](https://llms-explorer.com/tree/mac-local-llms-llama-cpp-internals/) · 1 facets · 20 facts · page: https://llms-explorer.com/tree/llama-cpp-jinja-runtime-minja-replacement-tojson/

## Facts

- The README says the engine "was introduced in PR#18462", lives in `common/jinja`, was originally inspired by huggingface.js's jinja package, and avoids C++ operator overloading. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/README.md)
- PR 18462 (ngxson, 2025-12-29) says the engine "may (or may not?) replace minja", was tested on 370 templates with 14 failures versus 8 for minja, and leaves input marking implemented but unused until a server follow-up. — [source](https://github.com/ggml-org/llama.cpp/pull/18462)
- PR 18462 regroups all chat-template workarounds in `common/chat.cpp` under a `workaround` namespace so they run on the data before it enters the runtime. — [source](https://github.com/ggml-org/llama.cpp/pull/18462)
- Input marking uses `jinja::string` with an `is_input` flag; one-to-one transforms preserve it, and split or join results are marked only if all input parts are marked; it is enabled by `global_from_json` with `mark_input = true`. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/README.md)
- Input-marking caveats: special tokens dynamically built from user input (for example `'<|' + message['role'] + '|>'`) will not function, and a prepended space such as `' ' + message['content']` becomes its own token. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/README.md)
- `tojson` takes `ensure_ascii`, `indent`, `separators` and `sort_keys`; `ensure_ascii` and `sort_keys` default to false when undefined. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- `tojson(sort_keys=true)` throws `not_implemented_exception("tojson sort_keys=true not implemented")`. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- `tojson` item separator defaults to `", "` when `indent` is negative or unset and `","` when an indent is given, and the key separator defaults to `": "`; a `separators` array overrides them. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- With `ensure_ascii=true`, non-ASCII code points become `\uXXXX` escapes (surrogate pairs above U+FFFF) and invalid UTF-8 becomes `�`, applied only inside JSON strings. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- On ints and floats the `safe` and `string` filters are bound to `tojson`, and on strings `tojson` is also bound. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- `apply_filter` aliases `count` to `length`, `d` to `default`, `e` to `escape` and `trim` to `strip` before lookup. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/runtime.cpp)
- `apply_filter` coerces non-string inputs to strings for `capitalize`, `lower`, `replace`, `strip`, `title`, `upper` and `wordcount`. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/runtime.cpp)
- An unknown filter throws `Unknown (built-in) filter '<name>' for type <type>`. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/runtime.cpp)
- `value.cpp` marks as not implemented: string `join`, object `join`, array `unique`, `replace` with a count argument, `format` beyond simple `{}` placeholders, `map` with filter-mapping, and the `escaped` and `filter` tests. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- `dictsort` is always case sensitive (a FIXME ignores `case_sensitive`) and accepts `by` (`value` or key) and `reverse`. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- `selectattr` and `rejectattr` throw `selectattr: unknown test '<name>'` for a test they do not know. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- `value.cpp` defines no builtin named `escape` or `sum` for arrays in the fetched file. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/common/jinja/value.cpp)
- The engine's test suite has dedicated `tojson ensure_ascii=true` cases, including nested objects and indent 2. — [source](https://raw.githubusercontent.com/ggml-org/llama.cpp/master/tests/test-jinja.cpp)
- llama.cpp commit d9f918d2 (2026-08-22), "common: add json.h abstraction (#27511)", is part of the move to decouple the engine from the JSON library. — [source](https://api.github.com/repos/ggml-org/llama.cpp/commits?path=tools/server/server-chat.cpp&per_page=30)
- Inferred: a Qwen-style template that pipes arguments through `tojson | safe` renders non-ASCII arguments as raw UTF-8 on llama.cpp, whereas a Python `json.dumps` default would escape them; byte-level prefix tests done in Python can differ. — source: `asserted`
