promptschema
Typed, versioned prompts for LLMs. Stop hardcoding AI prompts as strings. Define them as contracts.
npm install @dailybot/promptschema # TypeScript / JavaScript
pip install promptschema # Python
The problem
Every LLM project ends up with code like this:
// ❌ What most codebases look like today
const prompt = `You are an e-commerce assistant.
Order: ${order}
Language: ${lang}
${total > 100 ? "Offer 10% discount." : ""}
`
const result = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: prompt }]
})
No types. No validation. No version history.
If lang is missing, it silently breaks at runtime.
Nobody knows what version of this prompt is in production.
The solution
// ✅ With promptschema (TypeScript)
import { definePrompt, z } from '@dailybot/promptschema'
const orderPrompt = definePrompt({
name: 'order-assistant',
version: '1.0.0',
model: 'openai/gpt-4o',
input: z.object({
order: z.string(),
lang: z.enum(['es', 'en']),
total: z.number().positive(),
}),
template: (i) => `
You are an e-commerce assistant.
Order: ${i.order}, Language: ${i.lang}
${i.total > 100 ? 'Offer 10% discount.' : ''}
`
})
const result = await orderPrompt.run({ order: 'Dress #204', lang: 'en', total: 149 })
# ✅ With promptschema (Python)
from promptschema import define_prompt
from pydantic import BaseModel
from typing import Literal
@define_prompt(name='order-assistant', version='1.0.0', model='openai/gpt-4o')
class OrderPrompt(BaseModel):
order: str
lang: Literal['es', 'en']
total: float
def template(self) -> str:
discount = 'Offer 10% discount.' if self.total > 100 else ''
return f"""
You are an e-commerce assistant.
Order: {self.order}, Language: {self.lang}
{discount}
"""
result = await OrderPrompt(order='Dress #204', lang='en', total=149).arun()
Type-safe. Validated at build time. Version tracked.
Load from registry
Define prompts in one language, load them in another — from the same registry:
// TypeScript — load a prompt defined anywhere (TS or Python)
import { loadFromRegistry } from '@dailybot/promptschema'
const prompt = loadFromRegistry('order-assistant')
// prompt.name → 'order-assistant'
// prompt.version → '2.0.0'
// prompt.model → 'openai/gpt-4o'
const validated = prompt.validate({ order: 'Dress #204', lang: 'en', total: 149 })
const result = await prompt.run({ order: 'Dress #204', lang: 'en', total: 149 })
# Python — same registry, same prompt, same validation
from promptschema import load_from_registry
OrderPrompt = load_from_registry("order-assistant")
instance = OrderPrompt(order="Dress #204", lang="en", total=149)
result = await instance.arun()
The registry stores JSON Schema, so both languages reconstruct identical validation from a single source of truth.
Install
# TypeScript / JavaScript
npm install @dailybot/promptschema
# Python
pip install promptschema[openai] # OpenAI
pip install promptschema[anthropic] # Anthropic
pip install promptschema[all] # All providers
Requires Node >= 18 or Python >= 3.10.
Features
- 🔒 Type-safe — Zod (TS) and Pydantic (Python) schemas for every prompt input
- 🔖 Versioned — semantic versioning with automatic change detection
- 🔍 Diffable — readable diffs between prompt versions
- ⚡ Any model — OpenAI, Anthropic, Gemini, Ollama, or your own adapter
- 🌍 Dual — identical API in TypeScript and Python, shared registry
- 🔄 Cross-language — define in TS, load in Python (or vice versa) via
loadFromRegistry - 🪶 Lightweight — zero runtime dependencies beyond Zod/Pydantic
CLI
npx promptschema init # Create registry
npx promptschema status # Show sync state
npx promptschema bump order-assistant # Bump version
npx promptschema diff order-assistant 1.0.0 2.0.0 # Show diff
npx promptschema validate # CI gate (exit 1 if unsynced)
npx promptschema list # List all prompts
npx promptschema history order-assistant # Version timeline
The same commands work with Python: promptschema status, promptschema bump, etc.
Why promptschema?
| Raw strings | LangChain | promptschema | |
|---|---|---|---|
| Type-safe inputs | ❌ | ⚠️ partial | ✅ |
| Build-time validation | ❌ | ❌ | ✅ |
| Semantic versioning | ❌ | ❌ | ✅ |
| Prompt diff (readable) | ❌ | ❌ | ✅ |
| Works with any model | ✅ | ✅ | ✅ |
| TypeScript + Python | ✅ | ✅ | ✅ |
| Zero vendor lock-in | ✅ | ⚠️ partial | ✅ |
| Bundle size | 0kb | ~2MB | ~12kb |
Custom adapters
Register your own LLM provider in a few lines:
import { registerAdapter } from '@dailybot/promptschema'
registerAdapter('my-provider', {
name: 'my-provider',
async call({ model, prompt, temperature, maxTokens }) {
const response = await myLLMClient.generate({ model, prompt })
return {
text: response.text,
promptTokens: response.usage.input,
completionTokens: response.usage.output,
totalTokens: response.usage.total,
estimatedCost: 0,
}
},
})
Contributing
Contributions are welcome! Please open an issue first to discuss what you'd like to change.
git clone https://github.com/DailybotHQ/promptschema
cd promptschema
pnpm install
pnpm test
License
Release files for promptschema 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 | |
|---|---|---|---|
| promptschema-0.1.1.tar.gz | 23.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| promptschema-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.4 kB
Release files / promptschema-0.1.1.tar.gz
| Download URL | promptschema-0.1.1.tar.gz |
|---|---|
| Size | 23.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a0ae4840adcd83c3c162eacab9c862af55b176163788c01efc6f4aec024fd988
|
|
BLAKE2b-256 checksum How to use checksums |
b061a9077bb4f0e1d41ccb88ac20e608d9a531f6bb1b917007d2e549e7008a6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|
Release files / promptschema-0.1.1-py3-none-any.whl
| Download URL | promptschema-0.1.1-py3-none-any.whl |
|---|---|
| Size | 23.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
32a6af30a1339e4ec79ff674b82da3c78e4ca3eabb3024fd3f1e58b3f2bafcb6
|
|
BLAKE2b-256 checksum How to use checksums |
fd8718c5b7d6cdea3b611fc12c3d1531dea7dbaedb06b443cdf73f36a30f337f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|