pyrompt

pyrompt: Python Prompt Management

A flexible framework for managing, sharing, and searching prompts and prompt templates with support for multiple templating languages and idiomatic Python interfaces.

Quick Start:
>>> import tempfile
>>> from pyrompt import PromptCollection, TemplateCollection
>>> _base = tempfile.mkdtemp()
>>> prompts = PromptCollection('my_project', base_path=_base)
>>> templates = TemplateCollection('my_project', base_path=_base)
>>> prompts['system'] = "You are a helpful Python expert."
>>> templates['greeting.txt'] = "Hello, {name}!"
>>> print(templates.render('greeting.txt', name='Alice'))
Hello, Alice!
Main Components:
  • PromptCollection: Store and manage prompts

  • TemplateCollection: Store and manage templates with multi-engine support

  • PromptMall: Collection of collections

  • SemanticIndex: Semantic search over prompts

  • GitHubPromptCollection: GitHub-backed collections

class pyrompt.GitHubPromptCollection(repo: str, *, token: str | None = None, readonly: bool = True, branch: str = 'main', local_cache: str | None = None, collection_type: str = 'prompts')[source]

Prompt collection backed by GitHub repository.

Repositories must end with ‘_pyrompt’ suffix for discovery. Contains prompts/ and/or templates/ directories.

Examples

>>> # Publishing a collection
>>> gh = GitHubPromptCollection(
...     repo='username/my_prompts_pyrompt',
...     token='ghp_...',
...     readonly=False
... )
>>> gh['greeting'] = "Hello, {name}!"
>>> gh.sync()  # Commits and pushes to GitHub
sync(message: str = 'Update prompts via pyrompt')[source]

Push local changes to GitHub.

Parameters:

message – Commit message

Raises:

PermissionError – If collection is readonly

class pyrompt.PromptCollection(collection_name: str, *, base_path: str | None = None, with_metadata: bool = False, store_factory: Callable | None = None)[source]

Collection of prompts with MutableMapping interface.

Backed by file storage via dol, with optional metadata.

Examples

>>> import tempfile
>>> prompts = PromptCollection('my_project', base_path=tempfile.mkdtemp())
>>> prompts['system'] = "You are a helpful assistant."
>>> print(prompts['system'])
You are a helpful assistant.
>>> len(prompts)
1
class pyrompt.PromptMall(workspace_name: str, *, base_path: str | None = None, collection_names: List[str] | None = None, with_metadata: bool = False)[source]

Collection of collections - a “mall” of stores.

Provides nested access: mall[‘collection_name’][‘prompt_key’]

Examples

>>> mall = PromptMall('my_workspace')
>>> mall['system']['python_expert'] = "You are a Python expert."
>>> mall['templates']['greeting'] = "Hello {name}!"
>>> list(mall.keys())
['system', 'templates']
>>> results = mall.search('python')
add_collection(name: str, collection_type: str = 'prompt')[source]

Add a new collection to the mall.

Parameters:
  • name – Collection name

  • collection_type – ‘prompt’ or ‘template’

Example

>>> mall.add_collection('personas', 'prompt')
>>> mall['personas']['analyst'] = "You are a data analyst."
get_collection_type(name: str) str | None[source]

Get the type of a collection.

Parameters:

name – Collection name

Returns:

‘prompt’, ‘template’, or None if not found

items()[source]

Get (name, collection) pairs.

keys()[source]

Get collection names.

remove_collection(name: str)[source]

Remove a collection from the mall.

Note: This only removes it from the mall, not from disk.

Parameters:

name – Collection name

search(query: str, collections: List[str] | None = None, **search_kwargs) Dict[str, List[tuple]][source]

Search across multiple collections.

Parameters:
  • query – Search query

  • collections – Collection names to search (None = all)

  • **search_kwargs – Additional args for SemanticIndex.search

Returns:

Dict mapping collection_name -> search results

Example

>>> results = mall.search('python expert', top_k=3)
>>> for coll_name, matches in results.items():
...     print(f"\n{coll_name}:")
...     for key, score in matches:
...         print(f"  {key}: {score:.3f}")
values()[source]

Get collections.

class pyrompt.SemanticIndex(collection: Mapping[str, str], *, auto_update: bool = False, embedding_model: str = 'text-embedding-3-small', batch_size: int = 100)[source]

Semantic search index for prompts/templates.

Uses oa.embeddings to create vector representations, then supports similarity search.

Examples

>>> from pyrompt import PromptCollection, SemanticIndex
>>> prompts = PromptCollection('my_project')
>>> prompts['python'] = "You are a Python expert."
>>> prompts['data'] = "You specialize in data analysis."
>>> index = SemanticIndex(prompts)
>>> results = index.search("help with pandas", top_k=2)
add(key: str)[source]

Add single item to index.

Parameters:

key – Key of item to add

cluster(n_clusters: int = 5)[source]

Cluster prompts/templates into groups.

Parameters:

n_clusters – Number of clusters

Returns:

Dict mapping cluster_id -> list of keys

Raises:

ImportError – If scikit-learn not available

rebuild()[source]

Rebuild entire index from current collection.

remove(key: str)[source]

Remove item from index.

Parameters:

key – Key of item to remove

search(query: str, top_k: int = 5, filters: dict | None = None, diversity_threshold: float | None = None) List[Tuple[str, float]][source]

Search for similar prompts.

Parameters:
  • query – Search query text

  • top_k – Number of results to return

  • filters – Metadata filters (if collection has metadata)

  • diversity_threshold – If set, exclude results too similar to each other

Returns:

List of (key, similarity_score) tuples, sorted by score descending

Example

>>> results = index.search("help with data analysis", top_k=3)
>>> for key, score in results:
...     print(f"{key}: {score:.3f}")
class pyrompt.TemplateCollection(collection_name: str, *, base_path: str | None = None, with_metadata: bool = False, default_engine: str = 'format')[source]

Collection of templates with multi-engine support.

Automatically detects template engine based on file extension or content. Provides rendering capabilities.

Examples

>>> import tempfile
>>> templates = TemplateCollection('my_project', base_path=tempfile.mkdtemp())
>>> templates['greeting.txt'] = "Hello {name}!"
>>> templates.render('greeting.txt', name='Alice')
'Hello Alice!'
>>> # With Jinja2 (if installed)
>>> templates['greeting.jinja2'] = "Hello {{ name }}!"
>>> templates.render('greeting.jinja2', name='Bob')
'Hello Bob!'
create_prompt_functions(keys: List[str] | None = None, **common_kwargs)[source]

Create an aix.PromptFuncs collection from templates (one function per key).

LLM generation routes through aix (lazy import).

Parameters:
  • keys – Template keys to include (None = all)

  • **common_kwargs – Common kwargs for all prompt functions (e.g. ‘model’)

Returns:

aix.PromptFuncs object with a function for each template

Example

>>> import tempfile
>>> from pyrompt import TemplateCollection
>>> tc = TemplateCollection('demo', base_path=tempfile.mkdtemp())
>>> tc['greeting.txt'] = "Greet {name}"
>>> funcs = tc.create_prompt_functions()
>>> funcs['greeting.txt'](name='Alice')
'Hello Alice!'
parse(key: str) dict[source]

Parse a template to extract structure.

Returns dict with placeholders, defaults, metadata.

Parameters:

key – Template key

Returns:

Dict with ‘placeholders’, ‘defaults’, ‘metadata’

Example

>>> import tempfile
>>> templates = TemplateCollection('demo', base_path=tempfile.mkdtemp())
>>> templates['greeting.txt'] = "Hello {name}!"
>>> info = templates.parse('greeting.txt')
>>> info['placeholders']
['name']
render(key: str, **kwargs) str[source]

Render a template with provided values.

Parameters:
  • key – Template key

  • **kwargs – Values to inject

Returns:

Rendered template string

Example

>>> import tempfile
>>> templates = TemplateCollection('demo', base_path=tempfile.mkdtemp())
>>> templates['greeting.txt'] = "Hello {name}!"
>>> templates.render('greeting.txt', name='Alice')
'Hello Alice!'
to_prompt_function(key: str, **prompt_func_kwargs)[source]

Convert template to an AI-enabled function using aix.prompt_func.

LLM generation is routed through aix (the multi-provider facade) so the model/provider is switchable. aix is imported lazily, only when called.

Parameters:
  • key – Template key

  • **prompt_func_kwargs – Additional kwargs for aix.prompt_func (e.g., ‘model’, ‘temperature’, ‘name’)

Returns:

Callable function that invokes the LLM with the rendered template

Example

>>> import tempfile
>>> from pyrompt import TemplateCollection
>>> tc = TemplateCollection('demo', base_path=tempfile.mkdtemp())
>>> tc['explain.txt'] = "Explain {concept} in simple terms."
>>> explain = tc.to_prompt_function('explain.txt')
>>> explain(concept="quantum computing")
'Quantum computing is ...'
to_prompt_json_function(key: str, json_schema: dict, **prompt_func_kwargs)[source]

Convert template to a JSON-returning AI function.

Uses aix.prompt_func(output_schema=dict): aix requests JSON and parses it robustly (tolerating fenced output), returning a parsed dict. json_schema is accepted for API compatibility; aix does best-effort JSON rather than strict JSON-Schema enforcement. LLM generation routes through aix (lazy import).

Parameters:
  • key – Template key

  • json_schema – Desired JSON schema (kept for API compatibility)

  • **prompt_func_kwargs – Additional kwargs for aix.prompt_func

Returns:

Function that returns a parsed JSON dict

Example

>>> import tempfile
>>> from pyrompt import TemplateCollection
>>> tc = TemplateCollection('demo', base_path=tempfile.mkdtemp())
>>> tc['extract.txt'] = "Extract people from: {text}"
>>> extract = tc.to_prompt_json_function('extract.txt', {})
>>> extract(text="Alice met Bob")
{'people': ['Alice', 'Bob']}
class pyrompt.TemplateEngine[source]

Abstract base class for template engines.

Template engines parse and render templates with different syntaxes. They must provide: - name: Unique identifier (e.g., ‘format’, ‘jinja2’) - extensions: List of file extensions (e.g., [‘.jinja2’, ‘.j2’]) - parse_template: Extract placeholders and defaults - render: Render template with values - detect: Optionally detect if content uses this engine

detect(content: str) bool[source]

Detect if content uses this engine based on syntax.

Used when extension doesn’t clearly indicate engine. Override to provide content-based detection.

Parameters:

content – Template content

Returns:

True if content appears to use this engine

abstractmethod parse_template(template_str: str) dict[source]

Parse template to extract structure.

Parameters:

template_str – Template content

Returns:

  • ‘placeholders’: list of parameter names

  • ’defaults’: dict of default values

  • ’metadata’: any engine-specific info

Return type:

dict with keys

abstractmethod render(template_str: str, **kwargs) str[source]

Render template with provided values.

Parameters:
  • template_str – Template content

  • **kwargs – Values to inject

Returns:

Rendered string

pyrompt.clone_collection(repo: str, local_path: str, token: str | None = None)[source]

Clone a GitHub collection to local directory.

Parameters:
  • repo – Repository name (user/repo_pyrompt)

  • local_path – Local directory path

  • token – Optional GitHub token

Example

>>> clone_collection(
...     'thorwhalen/awesome_prompts_pyrompt',
...     '/tmp/my_prompts'
... )
pyrompt.create_project_structure(project_name: str, base_path: str | None = None, include_examples: bool = True) str[source]

Create a complete project structure for prompt management.

Creates directories and example files for a new pyrompt project.

Parameters:
  • project_name – Name of the project

  • base_path – Optional base path

  • include_examples – Whether to include example prompts

Returns:

Path to created project directory

Example

>>> path = create_project_structure('my_ai_app')
>>> print(f"Project created at: {path}")
pyrompt.detect_engine(content: str, extension: str = None) TemplateEngine[source]

Detect appropriate engine for content.

Priority: 1. Extension match (if provided) 2. Content-based detection 3. Default (format)

Parameters:
  • content – Template content

  • extension – Optional file extension

Returns:

TemplateEngine instance (never None, falls back to ‘format’)

pyrompt.discover_prompt_collections(search_term: str | None = None, min_stars: int = 0, language: str = 'Python', max_results: int = 50) List[dict][source]

Discover public *_pyrompt repositories on GitHub.

Parameters:
  • search_term – Search query (e.g., “python data”)

  • min_stars – Minimum star count

  • language – Programming language filter

  • max_results – Maximum number of results

Returns:

List of dicts with repo info (name, description, stars, url)

Example

>>> collections = discover_prompt_collections(
...     search_term='python',
...     min_stars=5
... )
>>> for repo in collections:
...     print(f"{repo['name']}: {repo['stars']} stars")
pyrompt.export_to_dict(collection, include_metadata: bool = True) Dict[str, Any][source]

Export collection to a dictionary.

Parameters:
  • collection – PromptCollection or TemplateCollection

  • include_metadata – Whether to include metadata

Returns:

Dict with ‘prompts’ and optionally ‘metadata’ keys

Example

>>> import tempfile
>>> from pyrompt import PromptCollection
>>> prompts = PromptCollection('my_project', base_path=tempfile.mkdtemp())
>>> prompts['system'] = 'You are helpful.'
>>> export_to_dict(prompts, include_metadata=False)
{'prompts': {'system': 'You are helpful.'}}
pyrompt.fork_collection(source: str, token: str, organization: str | None = None) GitHubPromptCollection[source]

Fork a collection to your account or organization.

Parameters:
  • source – Source repo (user/repo_pyrompt)

  • token – GitHub token with repo permissions

  • organization – Optional organization to fork to

Returns:

GitHubPromptCollection for the new fork

Example

>>> forked = fork_collection(
...     'thorwhalen/awesome_prompts_pyrompt',
...     token='ghp_...'
... )
pyrompt.get_default_base_path() str[source]

Get platform-appropriate base path for pyrompt data.

Returns:

%LOCALAPPDATA%/pyrompt - macOS/Linux: ~/.local/share/pyrompt

Return type:

  • Windows

pyrompt.get_engine(name: str) TemplateEngine | None[source]

Get engine by name.

Parameters:

name – Engine name (e.g., ‘format’, ‘jinja2’)

Returns:

TemplateEngine instance or None if not found

pyrompt.get_stats(collection) Dict[str, Any][source]

Get statistics about a collection.

Parameters:

collection – PromptCollection or TemplateCollection

Returns:

Dict with statistics

Example

>>> import tempfile
>>> from pyrompt import PromptCollection
>>> prompts = PromptCollection('my_project', base_path=tempfile.mkdtemp())
>>> get_stats(prompts)['total_prompts']
0
pyrompt.import_from_dict(collection, prompts: Dict[str, str], metadata: Dict[str, dict] | None = None)[source]

Import prompts from a dictionary.

Parameters:
  • collection – PromptCollection or TemplateCollection

  • prompts – Dict mapping keys to prompt/template strings

  • metadata – Optional dict mapping keys to metadata dicts

Example

>>> import tempfile
>>> from pyrompt import PromptCollection
>>> prompts = PromptCollection('my_project', base_path=tempfile.mkdtemp())
>>> import_from_dict(prompts, {'system': 'You are helpful.', 'user': 'Hello!'})
>>> sorted(prompts)
['system', 'user']
pyrompt.list_available_engines() Dict[str, Dict[str, Any]][source]

List all available template engines with their details.

Returns:

Dict mapping engine name to info dict

Example

>>> engines = list_available_engines()
>>> print(engines['format']['extensions'])
['.txt', '']
pyrompt.list_engines() List[str][source]

List all registered engine names.

Returns:

List of engine names

pyrompt.merge_collections(target, *sources, conflict_strategy: str = 'skip')[source]

Merge multiple collections into a target collection.

Parameters:
  • target – Target collection to merge into

  • *sources – Source collections to merge from

  • conflict_strategy – How to handle conflicts (‘skip’, ‘overwrite’, ‘error’)

Example

>>> import tempfile
>>> from pyrompt import PromptCollection
>>> base = tempfile.mkdtemp()
>>> target = PromptCollection('merged', base_path=base)
>>> source1 = PromptCollection('source1', base_path=base)
>>> source1['a'] = 'A'
>>> merge_collections(target, source1, conflict_strategy='skip')
>>> sorted(target)
['a']
pyrompt.quick_setup(project_name: str, with_templates: bool = True, with_metadata: bool = False, base_path: str | None = None) Dict[str, Any][source]

Quick setup for a new pyrompt project.

Creates both prompt and template collections with sensible defaults.

Parameters:
  • project_name – Name of the project

  • with_templates – Whether to create a template collection

  • with_metadata – Whether to enable metadata

  • base_path – Optional base path

Returns:

Dict with ‘prompts’ and optionally ‘templates’ keys

Example

>>> import tempfile
>>> collections = quick_setup('my_ai_project', base_path=tempfile.mkdtemp())
>>> collections['prompts']['system'] = "You are a helpful assistant."
>>> collections['templates']['greeting.txt'] = "Hello {name}!"
>>> sorted(collections)
['prompts', 'templates']
pyrompt.register_engine(engine: TemplateEngine)[source]

Register a template engine.

Parameters:

engine – TemplateEngine instance to register

pyrompt.render_template_file(file_path: str, output_path: str | None = None, **kwargs) str[source]

Render a template file directly.

Parameters:
  • file_path – Path to template file

  • output_path – Optional path to save rendered output

  • **kwargs – Template parameters

Returns:

Rendered string

Example

>>> result = render_template_file(
...     'templates/greeting.txt',
...     name='Alice'
... )
pyrompt.validate_template(template_str: str, engine_name: str = 'format', required_params: List[str] | None = None) Dict[str, Any][source]

Validate a template string.

Parameters:
  • template_str – Template content

  • engine_name – Engine to use (‘format’, ‘jinja2’, ‘mustache’)

  • required_params – Optional list of required parameter names

Returns:

Dict with ‘valid’, ‘errors’, ‘warnings’, ‘placeholders’

Example

>>> result = validate_template("Hello {name}!", required_params=['name'])
>>> assert result['valid']
>>> result = validate_template("Hello {name}!", required_params=['name', 'age'])
>>> assert not result['valid']