This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
promptfw — Prompt Template Framework
5-layer Jinja2 template engine for LLM applications.
Installation
pip install promptfw
# With accurate token counting:
pip install promptfw[tiktoken]
# All optional dependencies:
pip install 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)
5-Layer Stack
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
from promptfw import extract_field, extract_json
# LLMs often respond with Markdown key:value text instead of 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="") # → ""
# 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
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 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 |
Metadata
Release files for promptfw 0.5.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 | |
|---|---|---|---|---|
| promptfw-0.5.1.tar.gz | 45.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| promptfw-0.5.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 73.5 kB
Release files / promptfw-0.5.1.tar.gz
| Download URL | promptfw-0.5.1.tar.gz |
|---|---|
| Size | 45.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
df11b000a08603aa0cd7946ba37a46f0f9a725a9919c1a0ad9249dd945d40768
|
|
BLAKE2b-256 checksum How to use checksums |
2f821d852e6e0df5a75ea2f54b9c4913d405e57c2dbd063bae19ece52e140602
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|
Release files / promptfw-0.5.1-py3-none-any.whl
| Download URL | promptfw-0.5.1-py3-none-any.whl |
|---|---|
| Size | 28.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
549046213a5d12e0bd15a6602516e2bf6007d50dfe2d83cfb4def83b12acc1b2
|
|
BLAKE2b-256 checksum How to use checksums |
b25c347caf6701b8cba23cf361d5b3fa39fcb29371c683063aeea968c0c4949d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|
Security for promptfw 0.5.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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.