{"id":15809109,"url":"https://github.com/madbomber/prompt_manager","last_synced_at":"2025-10-14T10:05:37.660Z","repository":{"id":207653055,"uuid":"719754461","full_name":"MadBomber/prompt_manager","owner":"MadBomber","description":"Provides a simple way to manage prompts for a generative AI system.","archived":false,"fork":false,"pushed_at":"2025-09-01T23:45:04.000Z","size":2413,"stargazers_count":22,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-08T02:58:00.436Z","etag":null,"topics":["gem","genai","prompt","prompt-engineering","prompt-toolkit","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MadBomber.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-11-16T20:43:58.000Z","updated_at":"2025-09-25T06:41:25.000Z","dependencies_parsed_at":"2025-06-04T22:01:46.921Z","dependency_job_id":"f26d0b1f-5f6b-4edc-81e2-ddffdcd7fa0c","html_url":"https://github.com/MadBomber/prompt_manager","commit_stats":null,"previous_names":["madbomber/prompt_manager"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/MadBomber/prompt_manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadBomber%2Fprompt_manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadBomber%2Fprompt_manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadBomber%2Fprompt_manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadBomber%2Fprompt_manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MadBomber","download_url":"https://codeload.github.com/MadBomber/prompt_manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MadBomber%2Fprompt_manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279008861,"owners_count":26084517,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gem","genai","prompt","prompt-engineering","prompt-toolkit","ruby"],"created_at":"2024-10-05T03:09:17.398Z","updated_at":"2025-10-14T10:05:37.653Z","avatar_url":"https://github.com/MadBomber.png","language":"Ruby","readme":"# PromptManager\n\n\u003e [!CAUTION]\n\u003e ## ⚠️ Breaking Changes are Coming ⚠️\n\u003e See [Roadmap](#roadmap) for details about upcoming changes.\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ctable\u003e\n    \u003ctr\u003e\n      \u003ctd width=\"40%\" align=\"center\" valign=\"top\"\u003e\n        \u003ca href=\"https://madbomber.github.io/blog/\" target=\"_blank\"\u003e\n          \u003cimg src=\"prompt_manager_logo.png\" alt=\"PromptManager - The Enchanted Librarian of AI Prompts\" width=\"800\"\u003e\n        \u003c/a\u003e\n        \u003cbr /\u003e\u003cbr /\u003e\n        [Comprehensive Documentation Website](https://madbomber.github.io/prompt_manager/)\n      \u003c/td\u003e\n      \u003ctd width=\"60%\" align=\"left\" valign=\"top\"\u003e\n        Like an enchanted librarian organizing floating books of knowledge, PromptManager helps you masterfully orchestrate and organize your AI prompts through wisdom and experience. Each prompt becomes a living entity that can be categorized, parameterized, and interconnected with golden threads of relationships.\n        \u003cbr/\u003e\u003cbr/\u003e\n        \u003ch3\u003eKey Features\u003c/h3\u003e\n        \u003cul\u003e\n            \u003cli\u003e\u003cstrong\u003e📚 \u003ca href=\"#storage-adapters\"\u003eMultiple Storage Adapters\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e🔧 \u003ca href=\"#parameterized-prompts\"\u003eParameterized Prompts\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e📋 \u003ca href=\"#directive-processing\"\u003eDirective Processing\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e🎨 \u003ca href=\"#erb-and-shell-integration\"\u003eERB Integration\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e🌍 \u003ca href=\"#erb-and-shell-integration\"\u003eShell Integration\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e📖 \u003ca href=\"#comments-and-documentation\"\u003eInline Documentation\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e📊 \u003ca href=\"#parameter-history\"\u003eParameter History\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e⚡ \u003ca href=\"#error-handling\"\u003eError Handling\u003c/a\u003e\u003c/strong\u003e\n            \u003cli\u003e\u003cstrong\u003e🔌 \u003ca href=\"#extensible-architecture\"\u003eExtensible Architecture\u003c/a\u003e\u003c/strong\u003e\n        \u003c/ul\u003e\n      \u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\n\n## Table of Contents\n\n* [Installation](#installation)\n* [Quick Start](#quick-start)\n* [Core Features](#core-features)\n  * [Parameterized Prompts](#parameterized-prompts)\n    * [Keyword Syntax](#keyword-syntax)\n    * [Custom Patterns](#custom-patterns)\n    * [Working with Parameters](#working-with-parameters)\n  * [Directive Processing](#directive-processing)\n    * [Built\\-in Directives](#built-in-directives)\n    * [Directive Syntax](#directive-syntax)\n    * [Custom Directive Processors](#custom-directive-processors)\n  * [ERB and Shell Integration](#erb-and-shell-integration)\n    * [ERB Templates](#erb-templates)\n    * [Environment Variables](#environment-variables)\n  * [Comments and Documentation](#comments-and-documentation)\n    * [Line Comments](#line-comments)\n    * [Block Comments](#block-comments)\n    * [Blank Lines](#blank-lines)\n  * [Parameter History](#parameter-history)\n  * [Error Handling](#error-handling)\n* [Storage Adapters](#storage-adapters)\n  * [FileSystemAdapter](#filesystemadapter)\n    * [Configuration](#configuration)\n    * [File Structure](#file-structure)\n    * [Custom Search](#custom-search)\n    * [Extra Methods](#extra-methods)\n  * [ActiveRecordAdapter](#activerecordadapter)\n    * [Configuration](#configuration-1)\n    * [Database Setup](#database-setup)\n  * [Custom Adapters](#custom-adapters)\n* [Configuration](#configuration-2)\n  * [Initialization Options](#initialization-options)\n  * [Global Configuration](#global-configuration)\n* [Advanced Usage](#advanced-usage)\n  * [Custom Keyword Patterns](#custom-keyword-patterns)\n  * [Dynamic Directives](#dynamic-directives)\n  * [Search Capabilities](#search-capabilities)\n* [Examples](#examples)\n  * [Basic Usage](#basic-usage)\n  * [With Search](#with-search)\n  * [Custom Storage](#custom-storage)\n* [Extensible Architecture](#extensible-architecture)\n  * [Extension Points](#extension-points)\n  * [Potential Extensions](#potential-extensions)\n* [Roadmap](#roadmap)\n  * [v0\\.9\\.0 \\- Modern Prompt Format (Breaking Changes)](#v090---modern-prompt-format-breaking-changes)\n  * [v1\\.0\\.0 \\- Stability Release](#v100---stability-release)\n  * [Future Enhancements](#future-enhancements)\n* [Development](#development)\n* [Contributing](#contributing)\n* [License](#license)\n\n## Installation\n\nInstall the gem and add to the application's Gemfile by executing:\n\n    bundle add prompt_manager\n\nIf bundler is not being used to manage dependencies, install the gem by executing:\n\n    gem install prompt_manager\n\n## Quick Start\n\n```ruby\nrequire 'prompt_manager'\n\n# Configure storage adapter\nPromptManager::Prompt.storage_adapter =\n  PromptManager::Storage::FileSystemAdapter.config do |config|\n    config.prompts_dir = '~/.prompts'\n  end.new\n\n# Load and use a prompt\nprompt = PromptManager::Prompt.new(id: 'greeting')\nprompt.parameters = {\n  \"[NAME]\" =\u003e \"Alice\",\n  \"[LANGUAGE]\" =\u003e \"English\"\n}\n\n# Get the processed prompt text\nresult = prompt.to_s\n```\n\n## Core Features\n\n### Parameterized Prompts\n\nThe heart of PromptManager is its ability to manage parameterized prompts - text templates with embedded keywords that can be replaced with dynamic values.\n\n#### Keyword Syntax\n\nBy default, keywords are enclosed in square brackets: `[KEYWORD]`, `[MULTIPLE WORDS]`, or `[WITH_UNDERSCORES]`.\n\n```ruby\nprompt_text = \"Hello [NAME], please translate this to [LANGUAGE]\"\n```\n\n#### Custom Patterns\n\nYou can customize the keyword pattern to match your preferences:\n\n```ruby\n# Use {{mustache}} style\nPromptManager::Prompt.parameter_regex = /(\\{\\{[A-Za-z_]+\\}\\})/\n\n# Use :colon style\nPromptManager::Prompt.parameter_regex = /(:[a-z_]+)/\n```\n\nThe regex must include capturing parentheses `()` to extract the keyword.\n\n#### Working with Parameters\n\n```ruby\nprompt = PromptManager::Prompt.new(id: 'example')\n\n# Get all keywords found in the prompt\nkeywords = prompt.keywords  #=\u003e [\"[NAME]\", \"[LANGUAGE]\"]\n\n# Set parameter values\nprompt.parameters = {\n  \"[NAME]\" =\u003e \"Alice\",\n  \"[LANGUAGE]\" =\u003e \"French\"\n}\n\n# Get processed text with substitutions\nfinal_text = prompt.to_s\n\n# Save changes\nprompt.save\n```\n\n### Directive Processing\n\nDirectives are special line oriented instructions in your prompts that begin with `//` starting in column 1. They're inspired by IBM JCL and provide powerful prompt composition capabilities.  A character string that begins with `//` but is not at the very beginning of the line will NOT be processed as a directive.\n\n#### Built-in Directives\n\n**`//include` (alias: `//import`)** - Include content from other files:\n\n```text\n//include common/header.txt\n//import [TEMPLATE_NAME].txt\n\nMain prompt content here...\n```\n\nFeatures:\n- Loop protection prevents circular includes\n- Supports keyword substitution in file paths\n- Processes included files recursively\n\n#### Directive Syntax\n\n```text\n//directive_name [PARAM1] [PARAM2] options\n\n# Dynamic directives using keywords\n//[COMMAND] [OPTIONS]\n```\n\n#### Custom Directive Processors\n\nYou can create custom directive processors:\n\n```ruby\nclass MyDirectiveProcessor \u003c PromptManager::DirectiveProcessor\n  def process_directive(directive, prompt)\n    case directive\n    when /^\\/\\/model (.+)$/\n      set_model($1)\n    when /^\\/\\/temperature (.+)$/\n      set_temperature($1.to_f)\n    else\n      super\n    end\n  end\nend\n\nprompt = PromptManager::Prompt.new(\n  id: 'example',\n  directives_processor: MyDirectiveProcessor.new\n)\n```\n\n### ERB and Shell Integration\n\n#### ERB Templates\n\nEnable ERB processing for dynamic content generation:\n\n```ruby\nprompt = PromptManager::Prompt.new(\n  id: 'dynamic',\n  erb_flag: true\n)\n```\n\nExample prompt with ERB:\n\n```text\nToday's date is \u003c%= Date.today %\u003e\n\u003c% 5.times do |i| %\u003e\n  Item \u003c%= i + 1 %\u003e\n\u003c% end %\u003e\n```\n\n#### Environment Variables\n\nEnable automatic environment variable substitution:\n\n```ruby\nprompt = PromptManager::Prompt.new(\n  id: 'with_env',\n  envar_flag: true\n)\n```\n\nEnvironment variables are automatically replaced in the prompt text.\n\n### Comments and Documentation\n\nPromptManager supports comprehensive inline documentation:\n\n#### Line Comments\n\nLines beginning with `#` are treated as comments:\n\n```text\n# This is a comment\n# Description: This prompt does something useful\n\nActual prompt text here...\n```\n\n#### Block Comments\n\nEverything after `__END__` is ignored:\n\n```text\nMain prompt content...\n\n__END__\nDevelopment notes:\n- This section is completely ignored\n- Great for documentation\n- TODO items\n```\n\n#### Blank Lines\n\nBlank lines are automatically removed from the final output.\n\n### Parameter History\n\nPromptManager maintains a history of parameter values (since v0.3.0):\n\n```ruby\n# Parameters are stored as arrays\nprompt.parameters = {\n  \"[NAME]\" =\u003e [\"Alice\", \"Bob\", \"Charlie\"]  # Charlie is most recent\n}\n\n# The last value is always the most recent\ncurrent_name = prompt.parameters[\"[NAME]\"].last\n\n# Useful for:\n# - Implementing value history in UIs\n# - Providing dropdown selections\n# - Tracking parameter usage over time\n```\n\n### Error Handling\n\nPromptManager provides specific error classes for better debugging:\n\n```ruby\nbegin\n  prompt = PromptManager::Prompt.new(id: 'missing')\nrescue PromptManager::StorageError =\u003e e\n  # Handle storage-related errors\n  puts \"Storage error: #{e.message}\"\nrescue PromptManager::ParameterError =\u003e e\n  # Handle parameter substitution errors\n  puts \"Parameter error: #{e.message}\"\nrescue PromptManager::ConfigurationError =\u003e e\n  # Handle configuration errors\n  puts \"Configuration error: #{e.message}\"\nend\n```\n\n## Storage Adapters\n\nStorage adapters provide the persistence layer for prompts. PromptManager includes two built-in adapters and supports custom implementations.\n\n### FileSystemAdapter\n\nStores prompts as text files in a directory structure.\n\n#### Configuration\n\n```ruby\nPromptManager::Storage::FileSystemAdapter.config do |config|\n  config.prompts_dir       = \"~/.prompts\"      # Required\n  config.search_proc       = nil               # Optional custom search\n  config.prompt_extension  = '.txt'            # Default\n  config.params_extension  = '.json'           # Default\nend\n```\n\n#### File Structure\n\n```\n~/.prompts/\n├── greeting.txt        # Prompt text\n├── greeting.json       # Parameters\n├── email/\n│   ├── welcome.txt\n│   └── welcome.json\n```\n\n#### Custom Search\n\nIntegrate with external search tools:\n\n```ruby\nconfig.search_proc = -\u003e(query) {\n  # Use ripgrep for fast searching\n  `rg -l \"#{query}\" #{config.prompts_dir}`.split(\"\\n\")\n}\n```\n\n#### Extra Methods\n\n- `list` - Returns array of all prompt IDs\n- `path(id)` - Returns Pathname to prompt file\n\n### ActiveRecordAdapter\n\nStores prompts in a database using ActiveRecord.\n\n#### Configuration\n\n```ruby\nPromptManager::Storage::ActiveRecordAdapter.config do |config|\n  config.model              = PromptModel      # Your AR model\n  config.id_column          = :prompt_id       # Column for ID\n  config.text_column        = :content         # Column for text\n  config.parameters_column  = :params          # Column for parameters\nend\n```\n\n#### Database Setup\n\n```ruby\nclass CreatePrompts \u003c ActiveRecord::Migration[7.0]\n  def change\n    create_table :prompts do |t|\n      t.string :prompt_id, null: false, index: { unique: true }\n      t.text :content\n      t.json :params\n      t.timestamps\n    end\n  end\nend\n```\n\n### Custom Adapters\n\nCreate your own storage adapter:\n\n```ruby\nclass RedisAdapter\n  def initialize(redis_client)\n    @redis = redis_client\n  end\n\n  def get(id)\n    prompt_text = @redis.get(\"prompt:#{id}:text\")\n    parameters = JSON.parse(@redis.get(\"prompt:#{id}:params\") || '{}')\n    [prompt_text, parameters]\n  end\n\n  def save(id, text, parameters)\n    @redis.set(\"prompt:#{id}:text\", text)\n    @redis.set(\"prompt:#{id}:params\", parameters.to_json)\n  end\n\n  def delete(id)\n    @redis.del(\"prompt:#{id}:text\", \"prompt:#{id}:params\")\n  end\n\n  def list\n    @redis.keys(\"prompt:*:text\").map { |k| k.split(':')[1] }\n  end\nend\n```\n\n## Configuration\n\n### Initialization Options\n\nWhen creating a prompt instance:\n\n```ruby\nprompt = PromptManager::Prompt.new(\n  id: 'example',\n  context: ['additional', 'context'],\n  directives_processor: CustomProcessor.new,\n  external_binding: binding,\n  erb_flag: true,\n  envar_flag: true\n)\n```\n\nOptions:\n- `id` - Unique identifier for the prompt\n- `context` - Additional context array\n- `directives_processor` - Custom directive processor\n- `external_binding` - Ruby binding for ERB\n- `erb_flag` - Enable ERB processing\n- `envar_flag` - Enable environment variable substitution\n\n### Global Configuration\n\nSet the storage adapter globally:\n\n```ruby\nPromptManager::Prompt.storage_adapter = adapter_instance\n```\n\n## Advanced Usage\n\n### Custom Keyword Patterns\n\nExamples of different keyword patterns:\n\n```ruby\n# Handlebars style: {{name}}\nPromptManager::Prompt.parameter_regex = /(\\{\\{[a-z_]+\\}\\})/\n\n# Colon prefix: :name\nPromptManager::Prompt.parameter_regex = /(:[a-z_]+)/\n\n# Dollar sign: $NAME\nPromptManager::Prompt.parameter_regex = /(\\$[A-Z_]+)/\n\n# Percentage: %name%\nPromptManager::Prompt.parameter_regex = /(%[a-z_]+%)/\n```\n\n### Dynamic Directives\n\nCreate directives that change based on parameters:\n\n```text\n# Set directive name via parameter\n//[DIRECTIVE_TYPE] [OPTIONS]\n\n# Conditional directives\n//include templates/[TEMPLATE_TYPE].txt\n```\n\n### Search Capabilities\n\nImplement powerful search across prompts:\n\n```ruby\n# With FileSystemAdapter\nadapter.search_proc = -\u003e(query) {\n  # Custom search implementation\n  results = []\n  Dir.glob(\"#{prompts_dir}/**/*.txt\").each do |file|\n    content = File.read(file)\n    if content.include?(query)\n      results \u003c\u003c File.basename(file, '.txt')\n    end\n  end\n  results\n}\n\n# With ActiveRecordAdapter\nPromptModel.where(\"content LIKE ?\", \"%#{query}%\").pluck(:prompt_id)\n```\n\n## Examples\n\n### Basic Usage\n\n```ruby\n# examples/simple.rb\nrequire 'prompt_manager'\n\n# Setup\nPromptManager::Prompt.storage_adapter =\n  PromptManager::Storage::FileSystemAdapter.config do |c|\n    c.prompts_dir = '~/.prompts'\n  end.new\n\n# Create and use a prompt\nprompt = PromptManager::Prompt.new(id: 'story')\nprompt.parameters = {\n  \"[GENRE]\" =\u003e \"fantasy\",\n  \"[CHARACTER]\" =\u003e \"wizard\"\n}\n\nputs prompt.to_s\n```\n\n### Advanced Integration with LLM and Streaming\n\nSee [examples/advanced_integrations.rb](examples/advanced_integrations.rb) for a complete example that demonstrates:\n\n- **ERB templating** for dynamic content generation\n- **Shell integration** for environment variable substitution\n- **OpenAI API integration** with streaming responses\n- **Professional UI** with spinner feedback using `tty-spinner`\n\nThis example shows how to create sophisticated AI prompts that adapt to your system environment and stream responses in real-time.\n\n### With Search\n\nSee [examples/using_search_proc.rb](examples/using_search_proc.rb) for advanced search integration.\n\n### Custom Storage\n\n```ruby\n# examples/redis_storage.rb\nclass RedisStorage\n  # ... implementation\nend\n\nPromptManager::Prompt.storage_adapter = RedisStorage.new(Redis.new)\n```\n\n## Extensible Architecture\n\nPromptManager is designed to be extended:\n\n### Extension Points\n\n1. **Storage Adapters** - Implement your own persistence layer\n2. **Directive Processors** - Add custom directives\n3. **Search Processors** - Integrate external search tools\n4. **Serializers** - Support different parameter formats\n\n### Potential Extensions\n\n- **CloudStorageAdapter** - S3, Google Cloud Storage\n- **RedisAdapter** - For caching and fast access\n- **ApiAdapter** - REST API backend\n- **GraphQLAdapter** - GraphQL endpoint storage\n- **GitAdapter** - Version controlled prompts\n\n## Roadmap\n\n### v0.9.0 - Modern Prompt Format (Breaking Changes)\n- **Markdown Support**: Full `.md` file support with YAML front matter\n- **Modern Parameter Syntax**: Support for `{{keyword}}` format\n- **Enhanced API**: New `set_parameter()` and `get_parameter()` methods\n- **Parameter Validation**: Built-in validation based on specifications\n- **HTML Comments**: Support for `\u003c!-- comments --\u003e`\n- **Migration Tools**: Automated conversion utilities\n\n### v1.0.0 - Stability Release\n- Performance optimizations\n- Complete documentation\n- Production hardening\n\n### Future Enhancements\n- Additional storage adapters\n- Enhanced directive system with plugins\n- Prompt versioning and inheritance\n- Performance optimizations for large collections\n\n## Development\n\nLooking for feedback and contributors to enhance the capability of prompt_manager.\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at [https://github.com/MadBomber/prompt_manager](https://github.com/MadBomber/prompt_manager).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadbomber%2Fprompt_manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmadbomber%2Fprompt_manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadbomber%2Fprompt_manager/lists"}