Skip to main content

Prompty — Python Runtime

PyPI Python 3.11+

Prompty is a markdown file format (.prompty) for LLM prompts. The Python runtime loads, renders, parses, and executes these files. Every .prompty file becomes a typed Prompty object.

Installation

# Core + Jinja2 renderer + OpenAI provider
pip install prompty[jinja2,openai]

# Core + Microsoft Foundry provider
pip install prompty[jinja2,foundry]

# Core + Anthropic provider
pip install prompty[jinja2,anthropic]

# Everything (all renderers, providers, OpenTelemetry)
pip install prompty[all]

Extras

Extra Packages What it enables
[openai] openai OpenAI provider
[foundry] openai, azure-identity Microsoft Foundry provider
[anthropic] anthropic Anthropic provider
[jinja2] jinja2 Jinja2 template rendering
[mustache] chevron Mustache template rendering
[otel] opentelemetry-api OpenTelemetry tracing
[all] All of the above Everything

Quick Start

1. Write a .prompty File

---
name: greeting
model:
  id: gpt-4o-mini
  provider: openai
  connection:
    kind: key
    apiKey: ${env:OPENAI_API_KEY}
inputs:
  - name: name
    kind: string
    default: World
template:
  format:
    kind: jinja2
  parser:
    kind: prompty
---
system:
You are a friendly assistant.

user:
Say hello to {{name}}.

2. Run It

import prompty

# One-shot: load + prepare + run
result = prompty.invoke("greeting.prompty", inputs={"name": "Jane"})
print(result)

# Step-by-step
agent = prompty.load("greeting.prompty")
messages = prompty.prepare(agent, inputs={"name": "Jane"})
result = prompty.run(agent, messages)

3. Async

result = await prompty.invoke_async("greeting.prompty", inputs={"name": "Jane"})

API Reference

Core Functions

Function What it does
load(path) Parse .promptyPrompty
render(agent, inputs) Template → rendered string
parse(agent, rendered) Rendered string → list[Message]
prepare(agent, inputs) Render + parse + threads → list[Message]
run(agent, msgs) Executor + process → clean result
process(agent, resp) Extract content → clean result
invoke(prompt, inputs) Full pipeline: load + prepare + run
turn(prompt, ...) Full pipeline with tool-call loop
validate_inputs(...) Check required inputs present

All functions have _async variants (e.g., invoke_async, run_async, turn_async).

Agent Turns (Tool Calling)

def get_weather(location: str) -> str:
    return f"72°F and sunny in {location}"


result = prompty.turn(
    "my-agent.prompty",
    inputs={"question": "Weather in Seattle?"},
    tools={"get_weather": get_weather},
    max_iterations=10,  # default
)

The agent loop: calls the LLM, if it returns tool_calls, executes the matching functions, sends results back, repeats until the model returns a normal response or max_iterations is exceeded.

Error handling:

  • Bad JSON in tool arguments → error sent back to model for self-correction
  • Tool exception → error string sent back to model
  • Missing tool → error message sent back (no crash)
  • Max iterationsValueError raised

Connection Registry

For pre-configured SDK clients or token-based auth:

# .prompty file — reference a named connection
model:
  id: gpt-4o
  provider: foundry
  connection:
    kind: reference
    name: my-foundry
from openai import AzureOpenAI
from azure.identity import (
    DefaultAzureCredential,
    get_bearer_token_provider,
)

client = AzureOpenAI(
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    azure_ad_token_provider=get_bearer_token_provider(
        DefaultAzureCredential(),
        "https://cognitiveservices.azure.com/.default",
    ),
)
prompty.register_connection("my-foundry", client=client)

# Now run — executor resolves the client by name
result = prompty.invoke("my-prompt.prompty", inputs={...})

Structured Output

Define outputs in frontmatter to get JSON-parsed results:

outputs:
  - name: city
    kind: string
    description: The city name
  - name: temperature
    kind: integer
    description: Temperature in Fahrenheit

The executor sends this as OpenAI's response_format with json_schema, and the processor automatically JSON-parses the result.

Streaming

agent = prompty.load("chat.prompty")
messages = prompty.prepare(agent, inputs={"question": "Tell me a story"})

# Set stream option
agent.model.options.additionalProperties = {
    "stream": True,
}
response = prompty.run(agent, messages, raw=True)

# response is a PromptyStream — iterate for chunks
for chunk in prompty.process(agent, response):
    print(chunk, end="", flush=True)

Streaming handles tool call deltas (accumulated across chunks), refusal detection, and empty heartbeat chunks.

Tracing

from prompty import Tracer, PromptyTracer, trace

# Register a tracer
Tracer.add("console", prompty.console_tracer)
Tracer.add("json", PromptyTracer("./traces").tracer)

# All pipeline functions automatically emit traces
result = prompty.invoke("my-prompt.prompty", inputs={...})


# Custom functions
@trace
def my_function(): ...

OpenTelemetry integration:

from prompty.tracing.otel import otel_tracer

Tracer.add("otel", otel_tracer())

.prompty File Format

Structure

---
# YAML frontmatter (Prompty schema)
---
# Markdown body (becomes `instructions`)
# Uses role markers and template syntax

Role Markers

system:
You are a helpful assistant.

user:
{{question}}

assistant:
I'd be happy to help.

Thread Inputs

Conversation history is passed via a kind: thread input property:

inputs:
  - name: conversation
    kind: thread

Place {{conversation}} in the template where thread messages should be injected:

system:
You are a helpful assistant.
{{conversation}}
user:
{{question}}

The caller passes a list of messages as the thread input value.

Variable References

Syntax Purpose
${env:VAR} Env variable (required)
${env:VAR:default} Env variable with fallback
${file:path.json} Load file content from the prompt directory tree

${file:...} references are scoped to the containing .prompty file's directory by default. Pass allowed_file_roots to load() / load_async() only when the host application explicitly trusts additional shared directories.

Connection Kinds

Kind When to use
key API key auth (self-contained)
reference Pre-registered SDK client
anonymous Endpoint only, no credentials

Legacy Format Support

Prompty v1 .prompty files are automatically migrated with deprecation warnings. Key changes:

  • model.configurationmodel.connection
  • model.parametersmodel.options
  • inputs (dict format) → inputs (list of Property)
  • older input schema fields → inputs
  • older output schema fields → outputs
  • template: jinja2 → structured template with format and parser

Development

# Install for development
uv pip install -e ".[dev,all]"

# Unit tests (excludes integration by default)
uv run pytest tests/ -q

# Lint
uv run ruff check .
uv run ruff format --check .

# Integration tests (requires API keys in .env)
uv run pytest tests/integration/ -v -o "addopts="

License

See LICENSE in the repository root.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

prompty-2.0.0.tar.gz (174.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

prompty-2.0.0-py3-none-any.whl (306.8 kB view details)

Uploaded Python 3

File details

Details for the file prompty-2.0.0.tar.gz.

File metadata

  • Download URL: prompty-2.0.0.tar.gz
  • Upload date:
  • Size: 174.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for prompty-2.0.0.tar.gz
Algorithm Hash digest
SHA256 ef3f26549c92f916387d5d6170d5ba01bd2f854a15b95494dbfa889acb6cfa04
MD5 1d4b44cbca3c25ce31472ac9a31a9971
BLAKE2b-256 eaf2dedcae0162f67a7cee77f95d989a441fb68840d4a629ac96c7b7b7985f26

See more details on using hashes here.

Provenance

The following attestation bundles were made for prompty-2.0.0.tar.gz:

Publisher: prompty-python.yml on microsoft/prompty

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file prompty-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: prompty-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 306.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for prompty-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f023cfcbcc410e38fe161570cbf2aba4a34508b78fa679a31333c4cc1e4de334
MD5 f79141c44e6a8a28627bd6c0d97501ae
BLAKE2b-256 26ffd3c8d37d78bb195da7ccff3e0431509fb6427294a070037ed7f07c966d17

See more details on using hashes here.

Provenance

The following attestation bundles were made for prompty-2.0.0-py3-none-any.whl:

Publisher: prompty-python.yml on microsoft/prompty

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 files

0.1.50

2 files

0.1.49

2 files

0.1.48

2 files

0.1.47

2 files

0.1.46

2 files

0.1.45

2 files

0.1.44

2 files

0.1.40

2 files

0.1.39

2 files

0.1.38

2 files

0.1.37

2 files

0.1.36

2 files

0.1.34

2 files

0.1.33

2 files

0.1.24

2 files

0.1.23

2 files

0.1.22

2 files

0.1.21

2 files

0.1.20

2 files

0.1.19

2 files

0.1.18

2 files

0.1.17

2 files

0.1.16

2 files

0.1.15

2 files

0.1.14

2 files

0.1.13

2 files

0.1.12

2 files

0.1.10

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page