Skip to main content

Introduction

Deck by PromptPHP provides a clean, expressive API for loading, rendering, and managing versioned AI prompts in your Laravel application. Prompts are stored as plain files on disk and organised by name, version, and role. They are accessed through the Deck facade. A prompt can contain multiple roles (system, user, assistant, developer, tool, or any custom role you define). Each role’s content supports {{ $variable }} interpolation, and the entire prompt can be converted into a messages array ready to send to OpenAI, Anthropic, or any chat-completion API.

Retrieving prompts

The Deck facade

The Deck facade is the primary entry point for loading prompts. It delegates to the PromptManager singleton registered by the service provider:
The get method returns a PromptTemplate instance. If no version is specified, the active version is resolved automatically.

Dependency injection

You can also inject the PromptManager directly via Laravel’s service container:
The PromptManager is registered as a singleton, so the same instance is reused throughout the request lifecycle.

Active version

Use the active method to explicitly load the active version:
This is equivalent to calling get() without a version number.

Specific version

Pass a version number as the second argument to get to load a specific version, regardless of which version is currently active:
If the version does not exist, an InvalidVersionException is thrown.

Rendering roles

Once you have a PromptTemplate instance, you can render any role’s content with variable interpolation.

Dynamic role methods

The most expressive way to render a role is to call it as a method directly on the prompt instance. This uses PHP’s __call magic method and works for any role — not just system and user:
When called without arguments, the content is returned with placeholders left intact:

The role method

If the role name is dynamic or stored in a variable, use the explicit role method:
This is functionally identical to the magic method approach. If the role does not exist, an empty string is returned.

Raw content

To retrieve a role’s content without variable interpolation, use the raw method:
This is useful when you need to inspect the template, store it, or perform your own interpolation logic.

Inspecting prompts

Available roles

The roles method returns an array of all role names defined in the prompt:
Roles are discovered automatically from the files in the version directory. Any file matching the configured extension (e.g. .md) becomes a role — the filename (without extension) is the role name.

Checking for a role

Use the has method to check whether a specific role exists before attempting to render it:

Metadata

Metadata comes from two files, and metadata returns them merged:
  1. The prompt’s root metadata.json — shared by every version (name, description, and anything else you record there).
  2. The version’s own v{n}/metadata.json — specific to that one version.
Version-level keys win when both files define the same key, so a version can override the shared description without affecting its siblings.
Metadata is an associative array. If neither file exists, an empty array is returned.
The active_version key is never included. It records which version your application serves, which is routing state rather than metadata about the template you loaded. Read it with Deck::active() instead.

Name and version

Building messages for AI APIs

All roles

The toMessages method builds a messages array compatible with OpenAI, Anthropic, and other chat-completion APIs. It renders every role with the given variables and returns them in definition order:
This array can be passed directly to any AI API client:

Filtering roles

Pass a second argument to limit which roles are included and in what order:
Roles specified in the filter that don’t exist in the prompt are silently skipped.

Variable interpolation

Syntax

Deck by PromptPHP supports two placeholder syntaxes within prompt files: Both are replaced when you render a role with variables:
Use the spaced syntax ({{ $variable }}) for consistency with Laravel Blade conventions.

Supported value types

Values are cast to strings via PHP’s (string) cast, so you can pass any scalar or stringable value:

Missing variables

Placeholders that are not matched by the provided variables are left intact. This lets you render in stages or identify unfilled variables:

Versioning

Directory structure

Prompts are versioned using directory-based versioning. Each version lives in its own sub-directory (v1/, v2/, etc.) inside the prompt folder:
Only the active version is served. Creating a new version leaves active_version untouched, so you can draft in production and promote with prompt:activate when ready. Each version directory can contain:
  • Any number of role files (e.g. system.md, user.md, assistant.md)
  • An optional metadata.json for version-level metadata

Listing versions

Retrieve all versions for a prompt programmatically:
Versions are returned sorted in ascending order. Each entry includes the version number, the absolute path to the version directory, and any metadata from that version’s metadata.json. Or use the Artisan command:
See Artisan Commands — prompt:list for details.

Activating a version

Set a specific version as the active version:
The version accepts the same formats as Deck::get()2, '2', and 'v2' are equivalent. Anything that cannot be parsed throws InvalidVersionException. When database tracking is enabled, this updates the prompt_versions table — setting is_active = false on all versions of that prompt, then is_active = true on the specified version. When tracking is disabled, it writes the active_version key to the prompt’s root metadata.json file. Or use the Artisan command:
See Artisan Commands — prompt:activate for details.

Version resolution order

When you call Deck::get('name') without a version, the active version is resolved in this priority order:
  1. Database — If tracking is enabled, looks for a version marked is_active = true in the prompt_versions table for that prompt name.
  2. metadata.json — Reads the active_version key from the prompt’s root metadata.json file.
  3. Highest version — Falls back to the highest version number found on disk (e.g. if v1/ and v3/ exist, version 3 is used).
If no versions exist at all, an InvalidVersionException is thrown.

Caching

When caching is enabled, loaded prompts are stored in your configured cache store to avoid repeated filesystem reads:
The cache key follows the pattern {prefix}{name}.v{version}. Prompts are cached on first load and served from cache on subsequent requests until the TTL expires. Caching is automatically disabled when APP_DEBUG=true to ensure file changes are picked up immediately during development. See Configuration — Cache for the full reference.

Execution tracking

When database tracking is enabled, you can log prompt executions for performance monitoring, A/B testing, and audit trails:
All fields in the data array are optional. Records are inserted into the prompt_executions table. If tracking is disabled, the track method is a safe no-op. See Tracking & Performance for comprehensive documentation on the tracking system, database schema, and Eloquent models.
When using the Laravel AI SDK integration, the TrackPromptMiddleware handles execution tracking automatically — no manual track() calls needed.

Serialisation

The PromptTemplate class implements Laravel’s Arrayable contract. Call toArray() to get a serialisable representation:
This is useful for caching, logging, debugging, or passing prompt data to queued jobs.