Skip to main content

A lightweight prompt assembly library using sigil-based substitution with no template logic

Project description

prompt-assemble

A lightweight prompt assembly library for building dynamic prompts with sigil-based substitution. No logic in templates — templates stay dumb, logic stays in Python.

Features

  • Sigil-based substitution — Simple placeholder syntax ([[VAR_NAME]] and [[PROMPT: name]])
  • Format-agnostic — Works with loose XML, JSON, or plain text
  • Recursive substitution — Variable values can contain sigils, resolved in a second pass
  • Comments support — Single-line (#!) and multiline (<!-- -->) comments
  • No template logic — Loops, conditionals, and transforms belong in Python
  • Portable — Easy to use across different environments

Installation

pip install prompt-assemble

Quick Start

from prompt_assemble import assemble

template = """
<system>
You are a [[PROMPT: persona]] specializing in [[DOMAIN]].
</system>

<task>
[[PROMPT: task-instructions]]
</task>

<question>
[[QUESTION]]
</question>
"""

components = {
    "persona": "expert software architect",
    "task-instructions": "Analyze the code and provide recommendations.",
}

variables = {
    "DOMAIN": "Python development",
    "QUESTION": "How can we improve this function?",
}

result = assemble(template, components=components, variables=variables)
print(result)

Format Support

Loose XML

<system>You are a [[PROMPT: persona]]</system>
<task>[[PROMPT: task-instructions]]</task>

JSON

{
  "system": "You are a [[PROMPT: persona]]",
  "task": "[[PROMPT: task-instructions]]"
}

Plain Text

Subject: [[SUBJECT]]

Body:
[[BODY]]

Sigil Syntax

Sigil Purpose
[[VAR_NAME]] Simple variable substitution
[[PROMPT: name]] Inject a named prompt component
[[PROMPT_TAG: tag1, tag2]] Inject all prompts matching tags (AND intersection)
[[PROMPT_TAG:N: tag1, tag2]] Inject N most recent prompts matching tags

Comments

#! Single line comment

<!-- Multi-line
     comment -->

Comments are stripped before substitution and never reach the model.

Recursive Substitution

Variable values can themselves contain sigils:

variables = {
    "TASK": "Analyze [[CODE_TYPE]] code",
    "CODE_TYPE": "Python",
}

# Second pass resolves nested sigils

CLI Usage

pambl --template prompt.prompt --components components.json --variables vars.json

Database

PostgreSQL is required. The DatabaseSource implementation uses PostgreSQL-specific features including automatic reconnection on timeout and transaction management optimized for reliability.

PostgreSQL Support

  • PostgreSQL 10+ (required for production and testing)
  • Automatic connection reconnection on timeout
  • Multi-tenant support via table prefixes
  • Version history and tagging

Quick Setup with PostgreSQL

import psycopg2
from prompt_assemble.sources import DatabaseSource

# Connect to PostgreSQL
conn = psycopg2.connect(
    host="localhost",
    database="prompts",
    user="postgres",
    password="secret"
)

# Create source with table prefix for multi-tenant support
source = DatabaseSource(conn, table_prefix="prod_")

# Use with PromptProvider
from prompt_assemble import PromptProvider

provider = PromptProvider(source)

Docker Compose with PostgreSQL

See DOCKER.md for a complete Docker Compose setup with PostgreSQL.

Environment Variables

The prompt-assemble library and UI support the following environment variables for configuration:

Starting the UI Server

Use the provided startup script:

python start_ui_db.py

This script automatically:

  • Connects to PostgreSQL using environment variables
  • Initializes the database schema
  • Starts the Flask UI server
  • Creates tables with the configured prefix

Database Configuration (PostgreSQL)

Variable Type Default Description
DB_HOSTNAME string localhost PostgreSQL server hostname
DB_PORT int 5432 PostgreSQL server port
DB_USERNAME string postgres PostgreSQL username
DB_PASSWORD string (required) PostgreSQL password
DB_DATABASE string prompts PostgreSQL database name
DB_SSLMODE string require SSL mode: require, prefer, disable
DB_PREFIX string pambl_ Table name prefix (e.g., tables become pambl_prompts, pambl_prompt_tags)
PORT int 8000 Port for the Flask UI server

Example - Local PostgreSQL:

export DB_HOSTNAME=localhost
export DB_PORT=5432
export DB_USERNAME=postgres
export DB_PASSWORD=your_password
export DB_DATABASE=prompts
export DB_PREFIX=pambl_
export PORT=8000

python start_ui_db.py

Example - DigitalOcean Managed PostgreSQL:

export DB_HOSTNAME=db-postgresql-sfo2-xxxx-do-user-xxxxx-0.e.db.ondigitalocean.com
export DB_PORT=25060
export DB_USERNAME=pambl_user
export DB_PASSWORD=your_secure_password
export DB_DATABASE=pambl_db
export DB_SSLMODE=require
export DB_PREFIX=pambl_
export PORT=8000

python start_ui_db.py

Programmatic Configuration (Legacy)

Variable Type Default Description
PROMPT_ASSEMBLE_UI bool false Enable/disable the web UI server. Set to "true" to activate
PROMPT_ASSEMBLE_TABLE_PREFIX string "" (empty) Table prefix (deprecated - use DB_PREFIX instead)

Listener & Event Configuration

Variable Type Default Description
None currently - - Listener callbacks are configured programmatically

Configuration Examples

Development Environment (Local PostgreSQL)

export DB_HOSTNAME=localhost
export DB_PORT=5432
export DB_USERNAME=postgres
export DB_PASSWORD=dev_password
export DB_DATABASE=prompts_dev
export DB_SSLMODE=disable
export DB_PREFIX=dev_
export PORT=8000

python start_ui_db.py

Production (DigitalOcean PostgreSQL)

export DB_HOSTNAME=db-postgresql-sfo2-xxxxx-do-user-xxxxx-0.e.db.ondigitalocean.com
export DB_PORT=25060
export DB_USERNAME=prod_user
export DB_PASSWORD=your_secure_password
export DB_DATABASE=prompts_prod
export DB_SSLMODE=require
export DB_PREFIX=prod_
export PORT=8000

python start_ui_db.py

Testing

export DB_HOSTNAME=localhost
export DB_PORT=5432
export DB_USERNAME=postgres
export DB_PASSWORD=test_password
export DB_DATABASE=prompts_test
export DB_PREFIX=test_
export PORT=8001

python start_ui_db.py

Programmatic Configuration

You can also configure these settings directly in Python:

from prompt_assemble.sources import DatabaseSource
from prompt_assemble.api import run_server
import psycopg2

# Configure PostgreSQL database with table prefix
conn = psycopg2.connect(
    host="localhost",
    database="prompts",
    user="postgres",
    password="secret"
)
source = DatabaseSource(conn, table_prefix='myapp_')

# Configure Flask server
run_server(
    source=source,
    host='0.0.0.0',
    port=8000,
    debug=False
)

Quick Reference

All Environment Variables

# UI Server (Required for web interface)
PROMPT_ASSEMBLE_UI=true

# Flask Configuration (Optional)
FLASK_HOST=0.0.0.0
FLASK_PORT=8000
FLASK_DEBUG=false

# PostgreSQL Database Connection
DB_HOSTNAME=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=secret
DB_DATABASE=prompts

# Database Options
PROMPT_ASSEMBLE_TABLE_PREFIX=myapp_  # Table prefix for multi-tenancy

Database Driver

Install psycopg2 for PostgreSQL:

pip install psycopg2-binary

Connection Resilience

The DatabaseSource automatically handles connection timeouts and network interruptions:

  • Automatic reconnection — Detects closed connections and reconnects transparently
  • Health checks — Validates connection before each operation
  • Timeout recovery — Handles PostgreSQL idle timeout gracefully

No configuration required — reconnection happens automatically on these operations:

  • save_prompt() - Save/update prompts
  • delete_prompt() - Delete prompts
  • refresh() - Reload metadata
  • get_raw() - Fetch content
  • All variable set operations

Testing

Run the full test suite:

pytest tests/

Note: Database-specific tests require PostgreSQL:

# Skip database tests (for environments without PostgreSQL)
pytest tests/ -k "not test_database"

# Run only with PostgreSQL available
PGHOST=localhost PGUSER=postgres PGPASSWORD=secret PGDATABASE=test_prompts pytest tests/test_database_source.py

Test Coverage: 118 passing tests covering core library, FileSystem source, and listener system. PostgreSQL-specific tests are marked as requiring PostgreSQL.

Contributing

Contributions welcome! Please open an issue or submit a pull request.

License

MIT License — see LICENSE file for details.

Project details


Download files

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

Source Distribution

prompt_assemble-0.1.6.tar.gz (43.9 kB view details)

Uploaded Source

Built Distribution

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

prompt_assemble-0.1.6-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

Details for the file prompt_assemble-0.1.6.tar.gz.

File metadata

  • Download URL: prompt_assemble-0.1.6.tar.gz
  • Upload date:
  • Size: 43.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for prompt_assemble-0.1.6.tar.gz
Algorithm Hash digest
SHA256 bb47a905a62455298a99d227bd2653925a2e0fd6510047805880de26cf261b64
MD5 cd2e8f838d94bde6e7a035ab0ef48697
BLAKE2b-256 7456f060456b1bcaab76dce32e528c73d9059538d8496302d15a7e51164d97f5

See more details on using hashes here.

File details

Details for the file prompt_assemble-0.1.6-py3-none-any.whl.

File metadata

File hashes

Hashes for prompt_assemble-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 057928499948d0a1ae9b901dabb64dec5a4fed140f096e5734af6386d481cd02
MD5 d22cc2292bedbe1c38fc45b6b9397094
BLAKE2b-256 003ced59e7e672b005d8c8aad3bd328650211e5a4707e253cdc35dfdb752d7c5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page