AI Template Runner
Small local models are cheap and fast — they also lose structure the moment a prompt gets long. ait turns that weakness into a workflow: each template is a single Markdown file that gathers context, prompts the model, validates the answer and renders the result. Deterministic scaffolding around a dumb-but-fast model, even one running on your phone.
┌ template file ─────────────────────────────────┐
│ ```toml → model, endpoint, sampling │
│ ``` │
│ --- → system prompt │
│ user prompt: {cmd.version} output + question │
│ [test] / [out] → validate + render output │
└────────────────────────────────────────────────┘
One file, one command, one predictable answer — no agent framework needed.
Why it matters: a small model cannot keep a workflow in its head, but it can fill in a well-shaped slot. Templates put the workflow in the file so the model only has to do the part it is good at. Failures become visible and reproducible through [test], instead of vague "the model is dumb" sessions.
Quick start
Point ait at any OpenAI-compatible chat endpoint (llama.cpp server, Ollama, LM Studio, ...):
- Start a model server, e.g. llama.cpp:
llama-server -hf unsloth/Qwen3-0.6B-GGUF --port 8080
- Run a ready template:
uvx ai-template-runner run TEMPLATE "What is Python?"
Or clone the repository and try it against a fixture without a model at
all — the examples/simulation/ templates run against fixed
responses, so you can feel the [test]/[out] mechanics in seconds:
git clone https://github.com/brunodavi/ai-template-runner.git
cd ai-template-runner
uvx ai-template-runner run examples/simulation/conventional-commits/feat.md --test
Running on a phone? See docs/termux.md.
Installation
| Command | When to use |
|---|---|
uvx ai-template-runner --help |
zero-install trial from PyPI |
pipx install ai-template-runner |
persistent install, any platform (Termux ships pipx) |
pip install ai-template-runner |
any pip environment |
uv tool install ai-template-runner |
uv managed installs |
uv tool install git+https://github.com/brunodavi/ai-template-runner.git |
latest master |
Requires Python 3.12+. The CLI is ait (or ai-template-runner); the package has zero runtime dependencies.
Usage
ait run examples/features/full.md "What is Python?"
ait run examples/features/full.md "What is Python?" --quiet
ait run examples/simulation/conventional-commits/feat.md --test
ait --help
ait run --help
-q/--quiet: display only the AI response (stdout stays clean for pipes).-t/--test: validate the response against the template's[test]table. PASS/FAIL lines go to stderr and the exit code is 1 when any check fails.
Templates
Templates combine TOML configuration and Markdown prompts in a single file. The configuration is defined in a ```toml code block at the beginning of the file, and is parsed and removed from the prompt content. Two --- separators delimit an optional system prompt; everything after them becomes the user prompt. Templates can also execute terminal commands and inject their output directly into prompts.
```toml
[provider]
base_url = 'http://localhost:8080/v1/chat/completions'
model = 'lfm230m'
temperature = 0.2
top_p = 0.9
top_k = 40
min_p = 0.05
max_tokens = 220
seed = 42
stop = []
frequency_penalty = 0.0
presence_penalty = 0.0
repeat_penalty = 1.1
[provider.extras]
typical_p = 1.0
repeat_last_n = 64
[cmd]
message = 'echo hello'
```
---
You are a concise assistant. Use the command output as context.
---
Command output:
{cmd.message}
Answer the following question concisely: {question}
The TOML block is parsed and removed from the prompt content. The optional system prompt is delimited by two --- separators; everything after the second separator is the user prompt. When the separators are omitted, the whole content after the configuration block is the user prompt.
The {question} placeholder is replaced with the CLI input. The {cmd.message} placeholder executes the configured command and inserts its output into the prompt. Placeholders can be used in both the system and user prompts.
The provider supports these generation parameters:
temperature,top_p,top_k,min_p: control sampling.max_tokens: limits the generated response length.seed: sets the random seed when supported.stop: defines stop sequences.frequency_penalty,presence_penalty,repeat_penalty: control repetition.extras: passes additional parameters to the API, such as llama.cpp-specific options.
base_url and model are required. Parameter support depends on the API and model server being used.
A template can inherit configuration, commands, and prompts from another template with a top-level extends key placed before any TOML table:
extends = 'base.md'
[provider]
temperature = 0.2
The extends path is resolved relative to the template file itself, so examples/features/ templates use extends = '../base.md'. Child values win per key; nested tables such as [provider.extras] and [cmd] are merged key by key. Empty child prompts fall back to the parent prompts, which lets a template reuse only the parent prompts and configuration.
A template can validate its own output with a [test] table and the --test flag:
[test]
type = 'feat' # JSON output field equality
message = 'add health check endpoint' # exact value comparison
"user.name" = 'Alice' # nested JSON path (quoted dotted key)
text = 'exact raw output' # exact raw text comparison
text_contains = ['GET_health'] # every fragment present in the raw text
text_regex = '^\{' # regex search on the raw text
Run with validation:
ait run examples/simulation/conventional-commits/feat.md --test
PASS/FAIL lines go to stderr (stdout stays clean for pipes) and the exit code is 1 when any check fails. Missing JSON fields and invalid JSON output fail instead of raising. The [test] table participates in extends inheritance like the other config tables.
A template can also render its own display output with an [out] table. The text key is a render template formatted with the parsed JSON fields ({out.type}, {out.message}, ...); missing fields render as empty:
[out]
text = '{out.type}: {out.message}'
Transforms run in two channels that never share the field namespace (out.count is always the JSON field, never str.count):
[out]
text = '{out.message:strip} | {out.message:replace:GET:SET} | {out.message[:4]}'
[[out.upper]] # one step: str.upper() with no args
[[out.replace]] # named args match the real str signature
old = 'GET_health'
new = 'GET'
[[out.slice]] # helper: builtin slice(start, end)
start = 1
end = 10
The [[out.<method>]] tables run in real document order (one table = one step, an empty table means no arguments) and apply to the rendered text — or to the raw response when there is no text. Steps are real str methods, with named arguments mapped positionally by the real signature. The inline spec is a single step from method:arg1:arg2 (argument values may not contain ':'), and {out.field[1:]} follows pythonic slice syntax. Without [out] (or an empty table) the raw AI response is printed. The [out] config participates in extends inheritance per key: the child text and step lists replace the parent's.
The same inline transforms work on every interpolated value in the prompts — {question:strip}, {question[:80]:lower} and {cmd.message:upper}, {cmd.status[1:20]} — since the value stays lazy for {cmd.*} (the command only runs when a field is actually used).
Examples and docs
See examples/base.md for the shared base used by the examples, examples/features/ for one example per feature, examples/ for ready-to-use task templates such as email-subject.md and conventional-commits.md, and examples/simulation/ for simulations that run task templates against fixed fixtures.
For deeper material, read docs/architecture.md (why the code is
shaped the way it is), docs/termux.md (running local models on a phone)
and docs/maintenance.md (release routine for maintainers).
Development
git clone https://github.com/brunodavi/ai-template-runner.git
cd ai-template-runner
uv sync
uv pip install -e .
Editable installation (-e .) lets you run ait directly while developing, so source changes are available without reinstalling.
Run a template to test your changes:
ait run examples/features/full.md "What is Python?"
Run the test suite (from the repository root):
uv run python -m unittest
Contributions are welcome — CI runs the suite on Python 3.12, 3.13 and 3.14, so that is the floor.
Status
AIT is in active development for local AI experimentation and lightweight, template-driven workflows. Expect the template syntax to be stable and everything around it to keep evolving. See CHANGELOG.md for release history.
Licensed under the MIT license.
Metadata
Release files for ai-template-runner 1.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ai_template_runner-1.5.0.tar.gz | 13.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ai_template_runner-1.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.8 kB
Release files / ai_template_runner-1.5.0.tar.gz
| Download URL | ai_template_runner-1.5.0.tar.gz |
|---|---|
| Size | 13.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2bd1f95e9dc70c5ee9f2f5816e9db56d1324bebaca51600f3886811436dd6a1e
|
|
BLAKE2b-256 checksum How to use checksums |
2eddb9711fb86a15af5fa9166a0fc2306780a50648a1a624284d01ab74063be8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logRelease files / ai_template_runner-1.5.0-py3-none-any.whl
| Download URL | ai_template_runner-1.5.0-py3-none-any.whl |
|---|---|
| Size | 15.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fba5f3982fb7807df33c425d965d2a7c9421cc43e0867c6b77838c0a4c92d602
|
|
BLAKE2b-256 checksum How to use checksums |
ce5d304c6410b3d0a080383f0f7d24486d467e7420c8243a7530b55f5eee4c9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logSecurity for ai-template-runner 1.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ai_template_runner-1.5.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.