Variants & Registry¶
As your prompt library grows, you'll want to swap implementations without changing the code that uses them. The PromptRegistry maps logical names to prompt classes and lets you override which class is used at runtime.
Registering Prompts¶
use Cognesy\Xprompt\PromptRegistry;
$registry = new PromptRegistry();
$registry->register('reviewer.analyze', Analyze::class);
$prompt = $registry->get('reviewer.analyze');
echo $prompt->render(content: $doc);
Variants¶
Register multiple classes under the same name. The first registration becomes the default; subsequent ones are stored as variants:
$registry->register('reviewer.analyze', Analyze::class);
$registry->register('reviewer.analyze', AnalyzeCoT::class);
$registry->register('reviewer.analyze', AnalyzeConcise::class);
$registry->variants('reviewer.analyze');
// ['Analyze' => Analyze::class, 'AnalyzeCoT' => AnalyzeCoT::class, ...]
Overrides¶
Pass overrides to the constructor to swap which variant is returned by get():
$registry = new PromptRegistry(
overrides: ['reviewer.analyze' => AnalyzeCoT::class],
);
$prompt = $registry->get('reviewer.analyze');
// Returns AnalyzeCoT instance
Overrides are resolved by short class name or fully-qualified class name. This makes it easy to drive prompt selection from configuration files without changing calling code.
Creating Variants¶
A variant is just a subclass. Override what you need — template, model hint, body logic — and register it under the same name:
class Analyze extends Prompt
{
public string $model = 'sonnet';
public string $templateFile = 'analyze.twig';
public ?string $templateDir = __DIR__ . '/templates';
}
class AnalyzeCoT extends Analyze
{
public string $model = 'opus';
public string $templateFile = 'analyze_cot.twig';
}
The calling code doesn't change. It asks the registry for 'reviewer.analyze' and gets whichever variant is configured.
The AsPrompt Attribute¶
Instead of calling register() manually, annotate your class with #[AsPrompt]:
use Cognesy\Xprompt\Attributes\AsPrompt;
#[AsPrompt('reviewer.analyze')]
class Analyze extends Prompt
{
// ...
}
Then register via registerClass():
Auto-Discovery¶
PromptDiscovery scans Composer's classmap and registers all prompt classes automatically:
use Cognesy\Xprompt\Discovery\PromptDiscovery;
PromptDiscovery::register($registry, namespaces: ['App\\Prompts']);
Name resolution priority:
1. #[AsPrompt("name")] attribute
2. $promptName public property
3. Derived from FQCN — App\Prompts\Reviewer\AnalyzeDocument becomes reviewer.analyze_document
Listing Prompts¶
// Names only (excludes blocks by default)
$registry->names();
// ['reviewer.analyze', 'reviewer.summarize', ...]
// Include blocks
$registry->names(includeBlocks: true);
// Iterate name => class pairs
foreach ($registry->all() as $name => $class) {
echo "{$name}: {$class}\n";
}
Next Steps¶
- Configuration — configure template paths and engine settings
- Getting Started — revisit the basics