promptkit
A prompt template engine for LLM apps: validated variables, reusable few-shot blocks, and clean chat/message construction.
Part of the ragkit suite. Install with
pip install ragkit-promptkit, thenimport promptkit.
promptkit replaces scattered f-strings that silently break when a variable is missing. You define templates once, get up-front validation of required variables, compose few-shot prompts, and build OpenAI-style message lists without hand-assembling dicts. Zero third-party dependencies -- standard library only, Python 3.8+.
Install
pip install ragkit-promptkit
Local development (from promptkit/):
pip install -e .
Quick Start
Define a template, inspect its variables, and render it:
from promptkit import PromptTemplate
tmpl = PromptTemplate("Summarize the following {kind} in {n} sentences:\n\n{text}")
print(tmpl.variables) # {'kind', 'n', 'text'}
print(tmpl.render(kind="article", n=3, text="..."))
render() also accepts a single dict:
tmpl.render({"kind": "article", "n": 3, "text": "..."})
Missing variables are reported all at once
If a referenced variable has no value (and no default), you get a
MissingVariableError listing every missing name -- not just the first:
from promptkit import PromptTemplate, MissingVariableError
tmpl = PromptTemplate("{greeting}, {name}! Welcome to {place}.")
try:
tmpl.render(greeting="Hello")
except MissingVariableError as exc:
print(exc) # Missing required variable(s): 'name', 'place'
print(exc.missing) # ['name', 'place']
Extra/unknown keyword arguments are ignored, so you can safely pass a shared context dict to many templates.
Literal braces
Use {{ and }} for literal braces (same rules as str.format):
PromptTemplate('Return JSON like {{"score": {n}}}').render(n=5)
# Return JSON like {"score": 5}
Defaults and partial()
Provide defaults for optional variables, and use partial() to bake in some
values while leaving the rest open:
from promptkit import PromptTemplate
tmpl = PromptTemplate(
"You are a {tone} assistant. Answer: {question}",
defaults={"tone": "friendly"},
)
tmpl.render(question="What is Python?")
# "You are a friendly assistant. Answer: What is Python?"
# Bake in the tone, get a new reusable template:
sarcastic = tmpl.partial(tone="sarcastic")
sarcastic.render(question="What is Python?")
# "You are a sarcastic assistant. Answer: What is Python?"
An explicit value always overrides a default. partial() returns a new
template and never mutates the original.
Few-shot prompts
FewShotTemplate stitches a prefix, a list of rendered examples, and a
suffix (which usually holds the final user query):
from promptkit import FewShotTemplate
few = FewShotTemplate(
example_template="Q: {q}\nA: {a}",
examples=[
{"q": "2 + 2", "a": "4"},
{"q": "3 * 3", "a": "9"},
],
prefix="Solve the math problems.",
suffix="Q: {question}\nA:",
example_separator="\n\n",
)
# Add more examples dynamically:
few.add_example(q="10 - 4", a="6")
print(few.render(question="7 + 5"))
Output:
Solve the math problems.
Q: 2 + 2
A: 4
Q: 3 * 3
A: 9
Q: 10 - 4
A: 6
Q: 7 + 5
A:
Missing-variable validation applies across the prefix, examples, and suffix.
Chat prompts -> message dicts
ChatPromptTemplate builds OpenAI-style list[dict] message payloads. Each
message content is rendered with the same PromptTemplate rules, and missing
variables are aggregated across all messages:
from promptkit import ChatPromptTemplate, system, user, assistant
chat = ChatPromptTemplate.from_messages([
system("You are a helpful {role}."),
user("Explain {topic} to a {level} audience."),
])
messages = chat.render(role="tutor", topic="recursion", level="beginner")
# [
# {"role": "system", "content": "You are a helpful tutor."},
# {"role": "user", "content": "Explain recursion to a beginner audience."},
# ]
Pass messages straight to your LLM client. The system, user, and
assistant helpers just return (role, template) tuples. If you prefer typed
objects, chat.render_messages(...) returns Message(role, content) dataclass
instances (each has .to_dict()).
Prompt registry and versioning
PromptRegistry is a tiny in-memory store for named, versioned prompts. get()
returns the latest version by default:
from promptkit import PromptRegistry, PromptTemplate
registry = PromptRegistry()
registry.register(PromptTemplate("Summarize: {text}", name="summarize", version="1.0"))
registry.register(PromptTemplate("TL;DR the following:\n{text}", name="summarize", version="2.0"))
registry.list() # ['summarize']
registry.get("summarize") # v2.0 (latest)
registry.get("summarize", version="1.0") # the v1.0 template
latest = registry.get("summarize")
latest.render(text="...")
Versions are compared numerically when they look like dotted numbers
("1.0", "2.3"), falling back to string comparison otherwise.
API summary
| Object | Purpose |
|---|---|
PromptTemplate |
Single-string template with {var} placeholders, defaults, partial(), and .variables. |
FewShotTemplate |
Prefix + examples + suffix composition with add_example(). |
ChatPromptTemplate |
Renders (role, template) pairs to message dicts. |
Message |
dataclass(role, content) with .to_dict(). |
system / user / assistant |
Helpers returning (role, template) tuples. |
PromptRegistry |
In-memory register / get / list with versioning. |
MissingVariableError |
Raised with .missing listing every unresolved variable. |
License
MIT
Metadata
Release files for ragkit-promptkit 0.1.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 | |
|---|---|---|---|
| ragkit_promptkit-0.1.1.tar.gz | 12.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ragkit_promptkit-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.1 kB
Release files / ragkit_promptkit-0.1.1.tar.gz
| Download URL | ragkit_promptkit-0.1.1.tar.gz |
|---|---|
| Size | 12.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
33db66adcfeb324d59d739898980e5f87331b73d0d029963a12475d3640b5f2b
|
|
BLAKE2b-256 checksum How to use checksums |
6fa98c82a583a08cd04da6b4a359873b9f68a0901fe070eb2fa9d8adee6d68b6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.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 Jul 25, 2026.
Transparency logRelease files / ragkit_promptkit-0.1.1-py3-none-any.whl
| Download URL | ragkit_promptkit-0.1.1-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2de9e349d91aeea0f6e452811a6b972a5e2ff8d1ba9a99b3027f86b38f6bb69c
|
|
BLAKE2b-256 checksum How to use checksums |
a52a335ca824a8ede9fca0fdcfdb63797c1b291f18473a8ef716cd991105177e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.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 Jul 25, 2026.
Transparency log