Metadata-Version: 2.4
Name: prompt-template-manager
Version: 2.0.0
Summary: A lightweight Python library for managing, versioning, and composing reusable prompt templates.
Project-URL: Homepage, https://promptmanager.davman.dev
Author: Dave Manufor
License: MIT
Requires-Python: >=3.9
Requires-Dist: pyyaml>=6.0
Provides-Extra: all
Requires-Dist: anthropic>=0.25; extra == 'all'
Requires-Dist: tiktoken>=0.5; extra == 'all'
Requires-Dist: watchdog>=3.0; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.25; extra == 'anthropic'
Provides-Extra: test
Requires-Dist: hypothesis>=6.0; extra == 'test'
Requires-Dist: pytest-benchmark>=4.0; extra == 'test'
Requires-Dist: pytest-cov>=4.0; extra == 'test'
Requires-Dist: pytest>=7.0; extra == 'test'
Provides-Extra: tokenization
Requires-Dist: tiktoken>=0.5; extra == 'tokenization'
Provides-Extra: watch
Requires-Dist: watchdog>=3.0; extra == 'watch'
Description-Content-Type: text/markdown

# Prompt Template Manager (v2.0)

[![PyPI version](https://img.shields.io/pypi/v/prompt-template-manager.svg)](https://pypi.org/project/prompt-template-manager/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python Versions](https://img.shields.io/pypi/pyversions/prompt-template-manager.svg)](https://pypi.org/project/prompt-template-manager/)
[![Coverage Status](https://img.shields.io/badge/coverage-85%25-brightgreen.svg)](https://github.com/davemanufor/prompt-manager)

**Prompt Template Manager** is a definitive Python toolkit for engineering complex, versioned, and reusable LLM prompts. It transforms prompts from static strings into managed assets that can be composed, versioned for specific models, and hot-reloaded in production.

---

## 📖 Table of Contents
- [Quick Start](#-quick-start)
- [Installation](#-installation)
- [1. Configuration Architecture](#1-configuration-architecture)
  - [The YAML Schema](#the-yaml-schema)
  - [Prompt Versioning](#prompt-versioning)
  - [Chat/Messages Format](#chatmessages-format)
  - [Metadata (`_meta`)](#metadata-_meta)
- [2. Template Logic & Substitution](#2-template-logic--substitution)
  - [Variable Resolution (`{var}`)](#variable-resolution-var)
  - [Recursive Includes (`{include}`)](#recursive-includes-include)
  - [Environment Variables (`{env:VAR}`)](#environment-variables-envvar)
  - [Global Context](#global-context)
- [3. API Reference: `PromptManager`](#3-api-reference-promptmanager)
- [4. API Reference: `Prompt`](#4-api-reference-prompt)
- [5. Advanced Patterns (Few-Shot, etc.)](#5-advanced-patterns)
- [6. CLI Documentation](#6-cli-documentation)
- [7. Performance & Best Practices](#7-performance--best-practices)

---

## ⚡ Quick Start

### 1. Define `prompts.yaml`
```yaml
system_persona:
  _default: helpful
  helpful: "You are a helpful assistant."

analyze_text:
  _default: v1
  v1: |
    {include system_persona}
    Summarize this: {text}
```

### 2. Run in Python
```python
from prompt_template_manager import PromptManager

# Load and fetch
manager = PromptManager("prompts.yaml")
prompt = manager.get("analyze_text")

# Format and print
print(prompt.format({"text": "LLMs are evolving."}))
```

---

## 💾 Installation

```bash
# Core library (PyYAML only)
pip install prompt-template-manager

# All features (Watchdog, Tiktoken, Anthropic SDK)
pip install "prompt-template-manager[all]"
```

---

## 1. Configuration Architecture

### The YAML Schema
The core of the library is the YAML configuration. A file can contain multiple prompts, each identified by a unique key.

#### Simple (Static) Prompt
Best for snippets that never change.
```yaml
footer: "End of prompt. Response required."
```

#### Versioned Prompt (Standard)
Required for prompts that evolve or require metadata.
```yaml
task_generator:
  _default: v2
  _meta:
    description: "Generates code tasks"
    author: "Dave"
  v1: "Task: {task}"
  v2: "Revised Task: {task}. Be concise."
```

### Prompt Versioning
You can use standard version keys (`v1`, `v2`) or **Model Tags** to optimize for specific LLMs.

```yaml
summarizer:
  _default: gpt-4
  gpt-4: "Summarize: {text}"
  claude-3: "Please summarize: {text}"
  llama-3: "Summ: {text}"
```

### Chat/Messages Format
Prompts can be defined as a list of role-content pairs.

```yaml
code_review:
  _default: v1
  v1:
    - role: system
      content: "You are a senior dev."
    - role: user
      content: "Check this {language} code:\n{code}"
```

### Metadata (`_meta`)
Metadata is a key-value store (Strings only) for tracking prompt provenance.
```yaml
my_prompt:
  _default: v1
  _meta:
    max_tokens: "500"
    temperature: "0.7"
  v1: "..."
```

---

## 2. Template Logic & Substitution

### Variable Resolution (`{var}`)
Any text in curly braces that isn't a reserved tag (`include` or `env`) is a variable.

| Mode | Usage | Behavior on Missing Variable |
| :--- | :--- | :--- |
| **Strict** | `p.format(data, strict=True)` | Raises `ValueError` listing missing keys. |
| **Non-Strict** | `p.format(data, strict=False)` | Leaves the placeholder as-is (e.g., `{missing_var}`). |

### Recursive Includes (`{include}`)
Inject one prompt into another. If the included prompt is versioned, its `_default` version is used.
```yaml
persona: "You are an AI."
task: "{include persona} Solve: {problem}"
```
*Note: Circular references will raise an `ImportError`.*

### Environment Variables (`{env:VAR}`)
Resolved at **load time** (when `PromptManager` is initialized). 
- **Success:** Replaces tag with `os.environ[VAR]`.
- **Failure:** Raises `ValueError` at load time if the variable is not set.

```yaml
system_warning: "Running in {env:ENVIRONMENT} mode."
```

### Global Context
Inject variables into every prompt managed by a specific `PromptManager`.
```python
manager = PromptManager("prompts.yaml", context={"app_id": "PTM-001"})
# Every prompt in this manager now knows {app_id}
```

---

## 3. API Reference: `PromptManager`

`PromptManager` is **thread-safe** for reading (`.get()`) after initialization.

### Initialization & Loading
```python
def __init__(
    self, 
    source_path: str | Path, 
    context: dict[str, Any] | None = None, 
    watch: bool = False
) -> None
```
- **source_path**: File or directory. If a directory, all `.yaml`/`.yml` files are loaded.
- **Collision Rule:** If multiple files define the same prompt name, `PromptManager` raises a `ValueError` during initialization to prevent ambiguous resolution.

### Hot Reloading (Watch Mode)
Requires `watchdog`. Automatically reloads the library when source files change.
```python
manager = PromptManager("prompts.yaml", watch=True)
```

### Retrieving Prompts (`.get`)
```python
def get(
    self, 
    name: str, 
    version: int | str | None = None, 
    model: str | None = None
) -> Prompt
```
- Raises `KeyError` if not found, providing Levenshtein-based suggestions (e.g., *"Did you mean 'summarize'?"*).

### Cataloging (`.list`)
```python
def list(self) -> list[dict[str, Any]]
```
Returns a list of dictionaries describing every loaded prompt, its versions, and required variables.

---

## 4. API Reference: `Prompt`

### Formatting & Substitution
```python
def format(
    self, 
    data: dict[str, Any], 
    strict: bool = True
) -> str | list[dict[str, str]]
```
Returns a string for text prompts, or a list of messages for chat prompts.

### Partial Application
```python
def partial(self, data: dict[str, Any]) -> Prompt
```
Fill some variables now, returning a **new** `Prompt` object for the remaining variables.

### Token Estimation
```python
def estimate_tokens(
    self, 
    provider: str = "openai", 
    model: str = "gpt-4"
) -> int
```
Requires `tiktoken` (OpenAI) or `anthropic` SDK. Raises `ImportError` if missing.

### SDK Compatibility
```python
def to_openai_messages(self, data: dict[str, Any]) -> list[dict[str, str]]
def to_anthropic_messages(self, data: dict[str, Any]) -> list[dict[str, str]]
```

---

## 5. Advanced Patterns

### Few-Shot Prompting
Use includes to manage your example bank separately from your task logic.

**YAML:**
```yaml
# examples.yaml
sentiment_examples: |
  Text: "I love this!" | Sentiment: Positive
  Text: "This is bad." | Sentiment: Negative

# classifier.yaml
classify_task: |
  {include sentiment_examples}
  Text: "{input_text}" | Sentiment:
```

### Model Migration / A/B Testing
```python
# Easily switch between model-optimized versions
p_gpt = manager.get("task", model="gpt-4")
p_claude = manager.get("task", model="claude-3")
```

---

## 6. CLI Documentation

### `validate`
Recursively checks all YAML files in a directory for syntax, type errors, and circular includes.
```bash
ptm validate ./prompts
```

### `list`
Prints a human-readable table of prompts, versions, and variables.
```bash
ptm list prompts.yaml
```

### `get`
Renders a prompt to STDOUT.
```bash
ptm get prompts.yaml my_prompt --version v1
```

---

## 7. Performance & Best Practices

1. **Include Caching:** `PromptManager` uses an internal LRU cache for resolved includes. Deeply nested templates resolve in constant time after the first access.
2. **Directory Loading:** We recommend a "One Domain per File" approach:
   - `prompts/auth_flow.yaml`
   - `prompts/data_extraction.yaml`
3. **Environment Isolation:** Use `{env:VAR}` for instructions that vary by deployment (e.g., `{env:LLM_SAFETY_LEVEL}`).

---
*Created by Dave Manufor — 2026*
