iil-promptfw — Prompt Template Framework
5-layer Jinja2 template engine for LLM applications.
Installation
pip install iil-promptfw
# With accurate token counting:
pip install "iil-promptfw[tiktoken]"
# All optional dependencies:
pip install "iil-promptfw[all]"
Quick Start
from promptfw import PromptStack, PromptTemplate, TemplateLayer
stack = PromptStack()
stack.register(PromptTemplate(
id="story.task.write",
layer=TemplateLayer.TASK,
template="Write a {{ genre }} story about {{ topic }} in {{ words }} words.",
variables=["genre", "topic", "words"],
))
rendered = stack.render("story.task.write", {
"genre": "fantasy",
"topic": "a dragon who learns to code",
"words": 500,
})
# rendered.system → system prompt (SYSTEM + FORMAT layers)
# rendered.user → user prompt (CONTEXT* + TASK layers)
Layer Stack (5 core layers + 3 context sub-layers)
SYSTEM → Role & base behaviour (stable, cacheable)
FORMAT → Format-specific rules (stable, cacheable)
CONTEXT → Generic runtime context (dynamic)
CONTEXT_PROJECT → Project-level context (dynamic, v0.5.0)
CONTEXT_CHAPTER → Chapter-level context (dynamic, v0.5.0)
CONTEXT_SCENE → Scene-level context (dynamic, v0.5.0)
TASK → Concrete task (dynamic)
FEW_SHOT → Examples (appended last)
rendered = stack.render_stack(
["system.base", "format.roman", "context.project", "context.scene", "task.write_scene"],
context={
"role": "professional author",
"project": "The Iron Throne",
"current_scene": "The forest at night",
"characters": "Alice, Bob",
}
)
Load Templates from YAML
# templates/story/task/write_scene.yaml
id: story.task.write_scene
layer: task
template: |
Write scene {{ scene_id }}: {{ scene_description }}
Characters: {{ characters }}
stack = PromptStack.from_directory("templates/")
rendered = stack.render("story.task.write_scene", context)
LiteLLM / OpenAI Direct Output
# render_to_messages() returns [{"role": ..., "content": ...}, ...] directly
messages = stack.render_to_messages(
["system.base", "few_shot.examples", "task.write"],
context={...},
)
# Pass directly to litellm.completion() or openai.chat.completions.create()
Format-Aware Filtering
# for_format() returns a new stack with only matching templates.
# Templates with format_type=None are always included (format-agnostic).
stack = get_planning_stack()
messages = stack.for_format("academic").render_to_messages(
["planning.system", "planning.task.premise"],
context={...},
)
Fallback Chains
# render_with_fallback() tries patterns in order; first match wins.
result = stack.render_with_fallback(
[
"writing.task.write_chapter.roman",
"writing.task.write_chapter",
"writing.task.default",
],
context={...},
)
# get_or_fallback() on the registry level:
template = registry.get_or_fallback([
"chapter_writer_v2",
"chapter_writer_v1",
"chapter_writer_default",
])
Wildcard Lookup & Version Pinning
# Wildcard
template = stack.registry.get("roman.*.scene_generation")
# Version-pinned
rendered = stack.render_stack(
["system.base@1.0.0", "format.roman", "task.write@2.1.0"],
context,
)
Markdown Response Parsing (v0.5.0+)
Extract named fields from LLM Markdown responses. Handles **Field:**,
Field:, and ### Field patterns — including the common LLM style where
the colon appears inside the bold markers (**Field:** value).
from promptfw import extract_field, extract_json
text = "**Premise:** A blacksmith discovers magic.\n**Themes:** Identity, Power"
extract_field(text, "Premise") # → "A blacksmith discovers magic."
extract_field(text, "Themes") # → "Identity, Power"
extract_field(text, "Missing", default="") # → ""
# Plain colon style
text2 = "Title: The Lost City\nAuthor: Jane Doe"
extract_field(text2, "Title") # → "The Lost City"
extract_field(text2, "Author") # → "Jane Doe"
# JSON extraction from fenced blocks or raw text
data = extract_json(llm_response) # dict | None
items = extract_json_list(llm_response) # list
data = extract_json_strict(llm_response) # dict or raises LLMResponseError
v0.5.5: Fixed continuation-text slicing bug where the header line itself could leak into multi-field responses. All
**Field:**andField:patterns now extract correctly regardless of position in the text.
Token Estimation
# tokens_estimate is auto-calculated at construction time when tiktoken is installed
from promptfw import PromptTemplate, TemplateLayer
tmpl = PromptTemplate(
id="task.write",
layer=TemplateLayer.TASK,
template="Write a short story about {{ topic }}.",
)
print(tmpl.tokens_estimate) # e.g. 9 (via tiktoken cl100k_base)
Django Integration
from promptfw import DjangoTemplateRegistry
# Load from Django ORM queryset
registry = DjangoTemplateRegistry.from_queryset(
PromptTemplateModel.objects.filter(is_active=True)
)
stack = PromptStack(registry=registry)
Context Sub-Layers (v0.5.0)
For hierarchical document structures (book → chapter → scene):
from promptfw import TemplateLayer, USER_LAYERS
# Available sub-layers (rendered in this order within user prompt):
# CONTEXT → CONTEXT_PROJECT → CONTEXT_CHAPTER → CONTEXT_SCENE → TASK
stack.render_stack(
["sys", "context.project", "context.chapter", "context.scene", "task"],
context={...},
)
# render_stack auto-sorts to canonical order regardless of list order
Hot Reload (dev mode)
pip install "iil-promptfw[hotreload]"
stack = PromptStack.from_directory("templates/")
stack.enable_hot_reload() # watches for YAML changes
Optional Dependencies
| Extra | Package | Feature |
|---|---|---|
tiktoken |
tiktoken≥0.6 | Accurate token counting |
hotreload |
watchdog≥4.0 | File-system hot reload |
django |
django≥4.2 | ORM queryset adapter |
all |
all above | Everything |
Changelog
See CHANGELOG.md.
Metadata
Release files for iil-promptfw 0.8.1
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 | |
|---|---|---|---|---|
| iil_promptfw-0.8.1.tar.gz | 82.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| iil_promptfw-0.8.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 138.9 kB
Release files / iil_promptfw-0.8.1.tar.gz
| Download URL | iil_promptfw-0.8.1.tar.gz |
|---|---|
| Size | 82.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7641842d638677874d6ca6fdecd92cb05ffcf47bb25f746a48607f544b2cedf
|
|
BLAKE2b-256 checksum How to use checksums |
9677fd479bc98c5da2989f1db58653972b9c730643fb9c99c7414e38b200dc4a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 19, 2026.
Transparency logRelease files / iil_promptfw-0.8.1-py3-none-any.whl
| Download URL | iil_promptfw-0.8.1-py3-none-any.whl |
|---|---|
| Size | 56.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
aee736af8aa8a1e7b0123b1c73124be1598ff92a8cebc789dbb9d7c186aabe29
|
|
BLAKE2b-256 checksum How to use checksums |
1c8028225dccdb733e012c764d20b4f705d97212fc0c2abd3a2fd757e7a84ddc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 19, 2026.
Transparency logSecurity for iil-promptfw 0.8.1
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 iil_promptfw-0.8.1.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 Jul 19, 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.
To learn more about protecting yourself from malicious actors, visit our package security documentation.