{"id":39440544,"url":"https://github.com/codeaholicguy/promptfmt","last_synced_at":"2026-01-18T04:19:24.946Z","repository":{"id":330424393,"uuid":"1117247924","full_name":"codeaholicguy/promptfmt","owner":"codeaholicguy","description":"A composable prompt formatting library with runtime parameter substitution and conditional logic","archived":false,"fork":false,"pushed_at":"2025-12-25T10:45:57.000Z","size":113,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-26T23:18:01.537Z","etag":null,"topics":["composable","formatting","prompt"],"latest_commit_sha":null,"homepage":"https://promptfmt.com","language":"TypeScript","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/codeaholicguy.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-12-16T03:36:18.000Z","updated_at":"2025-12-25T10:46:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/codeaholicguy/promptfmt","commit_stats":null,"previous_names":["codeaholicguy/promptfmt"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/codeaholicguy/promptfmt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeaholicguy%2Fpromptfmt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeaholicguy%2Fpromptfmt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeaholicguy%2Fpromptfmt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeaholicguy%2Fpromptfmt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codeaholicguy","download_url":"https://codeload.github.com/codeaholicguy/promptfmt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeaholicguy%2Fpromptfmt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28529500,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T00:39:45.795Z","status":"online","status_checked_at":"2026-01-18T02:00:07.578Z","response_time":98,"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":["composable","formatting","prompt"],"created_at":"2026-01-18T04:19:24.228Z","updated_at":"2026-01-18T04:19:24.937Z","avatar_url":"https://github.com/codeaholicguy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# promptfmt\n\nA composable prompt formatting library with runtime parameter substitution and conditional logic.\n\n## Features\n\n- **Component-based architecture**: Build prompts from composable components (role, goal, input, output, context, persona, tone, few-shots, guardrails, constraints, tasks, steps)\n- **Runtime parameter substitution**: Use template strings with `${paramName}` syntax\n- **Conditional logic**: Include/exclude components based on runtime conditions\n- **Fluent API**: Chain methods for intuitive prompt building\n- **Type-safe**: Full TypeScript support\n\n## Installation\n\n```bash\nnpm install promptfmt\n```\n\n## Quick Start\n\n```typescript\nimport { PromptBuilder, createCondition } from 'promptfmt';\n\nconst prompt = new PromptBuilder()\n  .role('You are a wise numerology guide')\n  .goal('Generate a numerology interpretation for ${userName}')\n  .input({\n    name: '${userName}',\n    birthday: '${birthday}',\n    numberType: '${numberType}',\n    numberValue: '${numberValue}'\n  })\n  .persona((params) =\u003e {\n    if (params.age \u003e 10) {\n      return 'The Steady Anchor persona';\n    }\n    return 'The Clear Mirror persona';\n  })\n  .output('Write ${maxSentences} sentences')\n  .constraints('Do not include predictions')\n  .build({ \n    userName: 'John',\n    birthday: '1990-01-01',\n    numberType: 'lifePath',\n    numberValue: 5,\n    age: 34,\n    maxSentences: 10\n  });\n```\n\n## Component Types\n\n### Role\nDefines the AI's role/identity.\n\n```typescript\nbuilder.role('You are a helpful assistant');\n```\n\n### Goal\nDefines the objective of the prompt.\n\n```typescript\nbuilder.goal('Answer user questions');\n```\n\n### Input\nDefines input data/parameters. Can accept strings or objects.\n\n```typescript\n// String format\nbuilder.input('Question: ${question}');\n\n// Object format (auto-formatted with \"- key: value\")\nbuilder.input({\n  name: '${userName}',\n  age: '${age}',\n  metadata: { key: 'value' } // Non-string values are JSON.stringify'd\n});\n// Results in:\n// \"- name: John\n// - age: 25\n// - metadata: {\\\"key\\\":\\\"value\\\"}\"\n```\n\n### Output\nDefines expected output format/requirements.\n\n```typescript\nbuilder.output('Write ${maxSentences} sentences');\n```\n\n### Context\nProvides background information.\n\n```typescript\nbuilder.context('Today is ${date}');\n```\n\n### Persona\nDefines character/personality traits.\n\n```typescript\nbuilder.persona('The Steady Anchor persona');\n```\n\n### Tone\nDefines communication style.\n\n```typescript\nbuilder.tone('Warm and supportive');\n```\n\n### Few-shots\nProvides example inputs/outputs. Can accept an array of strings which will be automatically formatted as \"Example 1:\", \"Example 2:\", etc.\n\n```typescript\n// Using array (auto-formatted)\nbuilder.fewShots([\n  'Input: Hello\\nOutput: Hi there!',\n  'Input: How are you?\\nOutput: I am doing well, thank you!'\n]);\n// Results in: \"Example 1:\\nInput: Hello\\nOutput: Hi there!\\n\\nExample 2:\\n...\"\n\n// Using string (manual formatting)\nbuilder.fewShots('Example 1: ...');\n\n// Using function that returns array\nbuilder.fewShots((params) =\u003e {\n  return ['Example one', 'Example two'];\n});\n```\n\n### Guardrails\nDefines safety/behavior boundaries. Can accept an array of strings which will be automatically prefixed with \"-\".\n\n```typescript\n// Using array (auto-prefixed)\nbuilder.guardrails([\n  'Do not provide medical advice',\n  'Do not share personal information',\n  'Always verify facts'\n]);\n// Results in: \"- Do not provide medical advice\\n- Do not share personal information\\n- Always verify facts\"\n\n// Using string (manual formatting)\nbuilder.guardrails('Do not provide medical advice');\n\n// Using function that returns array\nbuilder.guardrails((params) =\u003e {\n  return ['Rule one', 'Rule two'];\n});\n```\n\n### Constraints\nDefines limitations/rules. Can accept an array of strings which will be automatically prefixed with \"-\".\n\n```typescript\n// Using array (auto-prefixed)\nbuilder.constraints([\n  'Maximum 500 words',\n  'Response time under 2 minutes',\n  'Use simple language'\n]);\n// Results in: \"- Maximum 500 words\\n- Response time under 2 minutes\\n- Use simple language\"\n\n// Using string (manual formatting)\nbuilder.constraints('Maximum 500 words');\n\n// Using function that returns array\nbuilder.constraints((params) =\u003e {\n  return ['Constraint one', 'Constraint two'];\n});\n```\n\n### Tasks\nDefines list of tasks to perform. Can accept an array of strings which will be automatically prefixed with \"1.\", \"2.\", etc.\n\n```typescript\n// Using array (auto-prefixed)\nbuilder.tasks([\n  'Analyze the input',\n  'Generate response',\n  'Validate output'\n]);\n// Results in: \"1. Analyze the input\\n2. Generate response\\n3. Validate output\"\n\n// Using string (manual formatting)\nbuilder.tasks('1. Analyze the input\\n2. Generate response');\n\n// Using function that returns array\nbuilder.tasks((params) =\u003e {\n  return ['Task one', 'Task two'];\n});\n```\n\n### Steps\nDefines sequential steps to follow. Can accept an array of strings which will be automatically prefixed with \"Step 1:\", \"Step 2:\", etc.\n\n```typescript\n// Using array (auto-prefixed)\nbuilder.steps([\n  'Understand the requirements',\n  'Break down into tasks',\n  'Execute each task'\n]);\n// Results in: \"Step 1: Understand the requirements\\nStep 2: Break down into tasks\\nStep 3: Execute each task\"\n\n// Using string (manual formatting)\nbuilder.steps('Step 1: ...\\nStep 2: ...');\n\n// Using function that returns array\nbuilder.steps((params) =\u003e {\n  return ['Step one', 'Step two'];\n});\n```\n\n## Parameter Substitution\n\nUse `${paramName}` syntax in template strings:\n\n```typescript\nbuilder.role('Hello ${name}, you are ${age} years old');\nconst result = builder.build({ name: 'John', age: 25 });\n// Result: \"Hello John, you are 25 years old\"\n```\n\n**Missing Parameters**: If a parameter is missing, null, or undefined, the placeholder is kept as-is (allows for optional parameters):\n\n```typescript\nbuilder.role('Hello ${name}');\nconst result = builder.build({}); // No params provided\n// Result: \"Hello ${name}\" (placeholder preserved)\n```\n\n**Non-string Values**: Non-string values are automatically converted to strings:\n\n```typescript\nbuilder.role('Age: ${age}, Active: ${active}');\nconst result = builder.build({ age: 25, active: true });\n// Result: \"Age: 25, Active: true\"\n```\n\nYou can also use functions for dynamic content:\n\n```typescript\nbuilder.role((params) =\u003e {\n  return `Hello ${params.name}, you are ${params.age} years old`;\n});\n```\n\n## Conditional Logic\n\nInclude/exclude components based on runtime conditions:\n\n```typescript\nimport { createCondition, RoleComponent, GoalComponent } from 'promptfmt';\n\nbuilder.goal('Goal A', {\n  condition: createCondition(\n    (params) =\u003e params.age \u003e 18,\n    new GoalComponent('Adult Goal'),\n    new GoalComponent('Child Goal')\n  )\n});\n\n// If age \u003e 18, includes \"Adult Goal\", otherwise includes \"Child Goal\"\nconst result = builder.build({ age: 25 });\n```\n\n**Multiple Components in Conditions**: You can include multiple components in the `then` or `else` clauses:\n\n```typescript\nbuilder.role('Base role', {\n  condition: createCondition(\n    (params) =\u003e params.userType === 'premium',\n    [\n      new RoleComponent('Premium role'),\n      new ContextComponent('Premium context')\n    ],\n    new RoleComponent('Standard role')\n  )\n});\n```\n\n**Conditional Logic Without Else**: If no `else` clause is provided and the condition is false, the component is excluded:\n\n```typescript\nbuilder.goal('Optional goal', {\n  condition: createCondition(\n    (params) =\u003e params.includeGoal === true,\n    new GoalComponent('Optional goal')\n    // No else clause - component excluded if condition is false\n  )\n});\n```\n\n## Component Ordering\n\nControl the order of components:\n\n```typescript\nbuilder.goal('Goal', { order: 2 });\nbuilder.role('Role', { order: 1 });\nbuilder.input('Input', { order: 3 });\n\n// Components will appear in order: Role, Goal, Input\n```\n\n**Ordering Rules**:\n- Components with lower order numbers appear first\n- Components without an explicit order come after ordered components, maintaining their insertion order\n- If no order is specified, components appear in the order they were added\n\n## Custom Labels\n\nAdd custom labels to components:\n\n```typescript\nbuilder.role('You are a helper', { label: 'System Role' });\n```\n\n## Advanced Usage\n\n### Adding Custom Components\n\nAll component classes are available for direct instantiation:\n\n```typescript\nimport { \n  RoleComponent, \n  GoalComponent, \n  InputComponent, \n  OutputComponent,\n  ContextComponent,\n  PersonaComponent,\n  ToneComponent,\n  FewShotsComponent,\n  GuardrailsComponent,\n  ConstraintsComponent,\n  TasksComponent,\n  StepsComponent,\n  BaseComponent\n} from 'promptfmt';\n\nconst customComponent = new RoleComponent('Custom role');\nbuilder.addComponent(customComponent);\n```\n\n### BaseComponent\n\nThe `BaseComponent` class provides a base for all components and includes a `clone` method:\n\n```typescript\nimport { BaseComponent, ComponentType } from 'promptfmt';\n\nconst component = new BaseComponent(ComponentType.ROLE, 'You are a helper');\nconst cloned = component.clone({ label: 'Custom Label' });\n// Creates a copy with updated properties\n```\n\n### Multiple Components\n\n```typescript\nbuilder.addComponents([\n  new RoleComponent('Role 1'),\n  new GoalComponent('Goal 1'),\n]);\n```\n\n### Clearing Components\n\n```typescript\nbuilder.clear();\n```\n\n### Empty Components\n\nEmpty components (with no content after parameter substitution) are automatically skipped during rendering.\n\n## API Reference\n\n### PromptBuilder\n\nMain class for building prompts.\n\n#### Methods\n\n- `role(content, options?)` - Add role component\n- `goal(content, options?)` - Add goal component\n- `input(content, options?)` - Add input component\n- `output(content, options?)` - Add output component\n- `context(content, options?)` - Add context component\n- `persona(content, options?)` - Add persona component\n- `tone(content, options?)` - Add tone component\n- `fewShots(content, options?)` - Add few-shots component\n- `guardrails(content, options?)` - Add guardrails component\n- `constraints(content, options?)` - Add constraints component\n- `tasks(content, options?)` - Add tasks component\n- `steps(content, options?)` - Add steps component\n- `addComponent(component)` - Add custom component\n- `addComponents(components)` - Add multiple components\n- `getComponents()` - Get all components\n- `clear()` - Clear all components\n- `build(params?)` - Build final prompt string. `params` is optional (defaults to `{}`). Missing parameters in template strings will keep their placeholders.\n\n### Utilities\n\n#### Parameter Substitution\n\n```typescript\nimport { \n  substitute, \n  resolveContent,\n  extractParameters, \n  validateParameters \n} from 'promptfmt';\n\n// Substitute parameters in a template string\nsubstitute('Hello ${name}', { name: 'John' }); // \"Hello John\"\n\n// Resolve content (handles strings, template strings, or functions)\nresolveContent('Hello ${name}', { name: 'John' }); // \"Hello John\"\nresolveContent((params) =\u003e `Hello ${params.name}`, { name: 'John' }); // \"Hello John\"\n\n// Extract parameter names from a template\nextractParameters('Hello ${name}, age ${age}'); // [\"name\", \"age\"]\n\n// Validate parameters (returns missing parameter names)\nvalidateParameters('Hello ${name}', { name: 'John' }); // [] (no missing params)\nvalidateParameters('Hello ${name}', {}); // [\"name\"] (missing params)\n\n// Validate with strict mode (throws error if params missing)\nvalidateParameters('Hello ${name}', {}, true); \n// Throws: Error(\"Missing required parameters: name\")\n```\n\n#### Conditional Logic\n\n```typescript\nimport { \n  createCondition, \n  evaluateCondition,\n  filterComponentsByCondition \n} from 'promptfmt';\nimport { RoleComponent, PromptComponent } from 'promptfmt';\n\n// Create a condition\nconst condition = createCondition(\n  (params) =\u003e params.age \u003e 18,\n  new RoleComponent('Adult'),\n  new RoleComponent('Child')\n);\n\n// Evaluate a condition and get components to include\nconst components = evaluateCondition(condition, { age: 25 });\n// Returns: [RoleComponent('Adult')]\n\n// Filter an array of components based on their conditions\nconst allComponents: PromptComponent[] = [/* ... */];\nconst activeComponents = filterComponentsByCondition(allComponents, { age: 25 });\n// Returns only components that pass their conditions\n```\n\n#### Prompt Rendering\n\n```typescript\nimport { \n  renderComponent, \n  renderComponents,\n  RenderOptions \n} from 'promptfmt';\nimport { RoleComponent } from 'promptfmt';\n\n// Render a single component\nconst component = new RoleComponent('You are a helper');\nconst rendered = renderComponent(component, {});\n// Returns: \"Role\\nYou are a helper\"\n\n// Render multiple components\nconst components = [\n  new RoleComponent('You are a helper'),\n  new GoalComponent('Help users')\n];\nconst prompt = renderComponents(components, {}, {\n  separator: '\\n\\n', // Default: '\\n\\n'\n  includeLabels: true, // Default: true\n  skipEmpty: true // Default: true\n});\n\n// Custom render options\nconst options: RenderOptions = {\n  separator: '\\n---\\n',\n  includeLabels: false,\n  labelFormatter: (component) =\u003e `[${component.type.toUpperCase()}]`,\n  skipEmpty: false\n};\n```\n\n**Default Component Labels**: When using `renderComponent` or `renderComponents`, default labels are automatically applied if no custom label is provided:\n- `role` → \"Role\"\n- `goal` → \"Goal\"\n- `input` → \"Input\"\n- `output` → \"Output\"\n- `context` → \"Context\"\n- `persona` → \"Persona\"\n- `tone` → \"Tone\"\n- `few-shots` → \"Examples\"\n- `guardrails` → \"Guardrails\"\n- `constraints` → \"Constraints\"\n- `tasks` → \"Tasks\"\n- `steps` → \"Steps\"\n\nNote: `PromptBuilder.build()` does not use these default labels - it only includes labels if explicitly set via the `label` option.\n\n### Types\n\nAll TypeScript types are exported for use in your code:\n\n```typescript\nimport type { \n  PromptComponent,\n  ComponentType,\n  ComponentOptions,\n  ParameterMap,\n  ContentValue,\n  TemplateString,\n  Condition,\n  ConditionFunction,\n  RenderOptions\n} from 'promptfmt';\n```\n\n- `PromptComponent` - Base interface for all components\n- `ComponentType` - Enum of all component types (`ROLE`, `GOAL`, `INPUT`, etc.)\n- `ComponentOptions` - Options for adding components (condition, order, label)\n- `ParameterMap` - Type for parameter objects (`Record\u003cstring, any\u003e`)\n- `ContentValue` - Content type: `string | TemplateString | ((params: ParameterMap) =\u003e string)`\n- `TemplateString` - Type alias for template strings\n- `Condition` - Conditional logic structure with `if`, `then`, and optional `else`\n- `ConditionFunction` - Function type: `(params: ParameterMap) =\u003e boolean`\n- `RenderOptions` - Options for rendering components (separator, includeLabels, labelFormatter, skipEmpty)\n\n## Examples\n\nSee the [`examples/`](examples/) directory for comprehensive examples demonstrating:\n- Basic usage\n- Parameter substitution\n- Conditional logic\n- Component ordering\n- Custom labels\n- Dynamic content with functions\n- All component types\n- Complex real-world scenarios\n\nRun examples with:\n```bash\nnpm run build\nnpx ts-node -r tsconfig-paths/register examples/run-all.ts\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeaholicguy%2Fpromptfmt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodeaholicguy%2Fpromptfmt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeaholicguy%2Fpromptfmt/lists"}