> ## Documentation Index
> Fetch the complete documentation index at: https://deck.promptphp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating prompts

> Generate versioned, role-based prompt structures with the `make:prompt` Artisan command.

## Introduction

Deck by PromptPHP provides an Artisan generator command that scaffolds versioned, role-based prompt structures for your AI agents. The command follows Laravel conventions and supports interactive workflows, automatic versioning, customisable stubs, and rich metadata.

## Generating prompts

### Basic usage

To create a new prompt, use the `make:prompt` Artisan command:

```bash theme={null}
php artisan make:prompt order-summary
```

This generates the following structure inside your configured prompts directory (default `resources/prompts`):

```
resources/prompts/
└── order-summary/
    ├── metadata.json          # Prompt-level: name, description, roles, active version
    └── v1/
        ├── metadata.json      # This version's own metadata
        └── system.md
```

A **system prompt** file is always created. Two `metadata.json` files are written: one at the prompt root recording the prompt's name, description, roles, and creation timestamp, and one inside the version directory recording that version alone.

### Interactive mode

Run the command without any arguments to enter a fully interactive flow:

```bash theme={null}
php artisan make:prompt
```

You will be guided through a series of questions:

1. **What should the prompt be named?** — Provide a name (automatically converted to kebab-case).
2. **Briefly describe this prompt (press Enter to skip)** — An optional description stored in `metadata.json`.
3. **Would you also like to create a user prompt file?** — Confirm to scaffold a `user.md` alongside `system.md`.
4. **Would you like to create prompt files for additional roles?** — Confirm, then enter comma-separated role names (e.g. `assistant, developer`).

<Note>
  The interactive description and user-prompt questions are only asked when
  the name argument is omitted. When passing a name directly, use the
  `--desc`, `--user`, and `--interactive` options instead.
</Note>

## Command signature

```
make:prompt {name?} {--from=} {--desc=} {--u|user} {--role=*} {--i|interactive} {--f|force}
```

### Arguments

| Argument | Required | Description                                                                                        |
| -------- | -------- | -------------------------------------------------------------------------------------------------- |
| `name`   | No       | The name of the prompt. Omit to be prompted interactively. Automatically normalised to kebab-case. |

### Options

| Option          | Shorthand | Description                                                              |
| --------------- | --------- | ------------------------------------------------------------------------ |
| `--from=`       |           | Path to a custom stub file to use as the user prompt template.           |
| `--desc=`       |           | A short description of what this prompt does. Stored in `metadata.json`. |
| `--user`        | `-u`      | Also create a `user` prompt file alongside the default `system` prompt.  |
| `--role=*`      |           | One or more additional roles to scaffold prompt files for. Repeatable.   |
| `--interactive` | `-i`      | Interactively choose which additional roles to create.                   |
| `--force`       | `-f`      | Overwrite an existing prompt's latest version without confirmation.      |

## Prompt structure

### Directory layout

Every prompt is organised into a named directory containing versioned sub-directories and a `metadata.json` file:

```
resources/prompts/
└── <prompt-name>/
    ├── v1/
    │   ├── system.md          # Always created
    │   ├── user.md            # Created with --user or -u
    │   ├── assistant.md       # Created with --role=assistant
    │   ├── developer.md       # Created with --role=developer
    │   └── metadata.json      # This version's metadata
    ├── v2/
    │   └── ...
    └── metadata.json          # Prompt-level metadata
```

The file extension is controlled by the `deck.extension` configuration value (default: `md`). For example, setting it to `txt` produces `system.txt`, `user.txt`, etc.

### Metadata

The command writes two metadata files: one at the prompt root describing the prompt as a whole, and one inside the version directory describing that version.

#### Prompt metadata

`<prompt-name>/metadata.json` is **merged**, never replaced, each time the command runs:

```json theme={null}
{
    "name": "order-summary",
    "description": "Summarises customer orders for the support agent.",
    "roles": ["system", "user", "assistant"],
    "variables": [],
    "created_at": "2025-01-15T10:30:00+00:00"
}
```

| Field         | Description                                                                                                                                              |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`        | The kebab-case prompt name.                                                                                                                              |
| `description` | A human-readable summary. Populated via `--desc=` or the interactive flow. Kept as-is when you create a new version without supplying a new description. |
| `roles`       | An ordered list of every role scaffolded for the version just created. Always starts with `system`.                                                      |
| `variables`   | Reserved for future use (template variable extraction). Never reset once you populate it.                                                                |
| `created_at`  | ISO 8601 timestamp of when the **prompt** was first created.                                                                                             |

Any other keys you add by hand are preserved — including `active_version`, so **scaffolding a new version never changes which version your application serves**. When another version is active, the command tells you how to promote the one you just created:

```
Version 2 of the [order-summary] prompt has been created successfully with the following roles: system.

v1 is still the active version.
Run `php artisan prompt:activate order-summary v2` to make v2 live.
```

#### Version metadata

`<prompt-name>/v{n}/metadata.json` records that version alone:

```json theme={null}
{
    "version": 2,
    "roles": ["system", "user"],
    "created_at": "2025-01-20T09:12:00+00:00"
}
```

Add your own keys here to override prompt-level metadata for a single version — see [Metadata](/core/prompts#metadata) for how the two files merge.

## Roles

### System role (default)

A `system.md` file is **always** created. This is the primary prompt file and represents the system-level instructions for your AI agent. No flag is needed:

```bash theme={null}
php artisan make:prompt code-reviewer
# Creates: resources/prompts/code-reviewer/v1/system.md
```

The default system prompt stub contains:

```markdown theme={null}
You are an AI assistant specialized in...

Follow these guidelines:

- Be helpful
- Use {{ $tone }} tone
```

### User role

To also scaffold a user prompt file, pass the `--user` (or `-u`) flag:

```bash theme={null}
php artisan make:prompt code-reviewer --user
# Creates: system.md + user.md
```

In the interactive flow (name omitted), you are asked whether to create a user prompt via a confirmation question.

The default user prompt stub contains:

```markdown theme={null}
# User prompt for {{ $name }}

Your task is to...

User input: {{ $input }}
```

### Extra roles

You can scaffold prompt files for any additional roles using the `--role` option. It is repeatable:

```bash theme={null}
php artisan make:prompt code-reviewer --role=assistant --role=developer
# Creates: system.md + assistant.md + developer.md
```

Role names are normalised to kebab-case (e.g. `ToolCall` becomes `tool-call.md`). Each role file uses the `role-prompt.stub` template with the `{{ $role }}` placeholder replaced by the actual role name.

The default role prompt stub contains:

```markdown theme={null}
# {role} prompt

You are acting in the {role} role.

Your task is to...
```

To choose roles interactively **without** omitting the name argument, pass `--interactive` (or `-i`):

```bash theme={null}
php artisan make:prompt code-reviewer -i
# Prompts: "Would you like to create prompt files for additional roles?"
# Then:    "Which roles? (comma-separated, e.g. assistant,developer)"
```

<Note>
  When `--role` values are provided explicitly, the interactive role prompt is
  skipped — explicit values always take precedence.
</Note>

All scaffolded roles (including `system` and optionally `user`) are recorded in the `roles` array of `metadata.json`.

## Versioning

Deck uses directory-based versioning. Each version lives in its own sub-directory (`v1/`, `v2/`, etc.) inside the prompt folder.

### Auto-increment

When you run the command for a prompt that already has one or more versions, you are presented with a choice:

```bash theme={null}
php artisan make:prompt code-reviewer
# ⚠ Prompt [code-reviewer] already exists at version 2.
# What would you like to do?
#   [version]    Create a new version (v3)
#   [overwrite]  Overwrite version 2
#   [cancel]     Cancel
```

Selecting **"Create a new version"** auto-increments the version number and creates a fresh directory (e.g. `v3/`). Existing versions remain untouched.

### Overwriting

Selecting **"Overwrite"** replaces the files in the latest version directory. The version number stays the same, but the prompt files are regenerated from the current stubs.

Selecting **"Cancel"** aborts the command without making any changes.

### Force mode

In non-interactive environments (CI pipelines, scripts), use `--force` (or `-f`) to overwrite the latest version without any prompts:

```bash theme={null}
php artisan make:prompt code-reviewer --force
```

If version 2 exists, `--force` overwrites `v2/` directly. It will **never** create a new version automatically — its purpose is to regenerate the latest version.

For brand-new prompts, `--force` has no special effect; `v1/` is created as normal.

## Stubs

The content of generated prompt files comes from **stub templates**. Three stubs ship with the package:

### Default stubs

| Stub                 | Used For         | Placeholders                                     |
| -------------------- | ---------------- | ------------------------------------------------ |
| `system-prompt.stub` | `system.md`      | `{{ $tone }}`                                    |
| `user-prompt.stub`   | `user.md`        | `{{ $name }}`, `{{ $input }}`                    |
| `role-prompt.stub`   | Extra role files | `{{ $role }}` (auto-replaced at generation time) |

The default stubs are located in the package's `stubs/` directory.

### Custom stubs

To customise the stubs for your project, create a `stubs/deck/` directory at your application root and place your own versions of any stub file there:

```
your-app/
└── stubs/
    └── deck/
        ├── system-prompt.stub
        ├── user-prompt.stub
        └── role-prompt.stub
```

Published stubs **always take precedence** over the package defaults. You only need to publish the stubs you want to override — any missing stubs fall back to the package defaults.

### Using a one-off template

To use a specific file as the user prompt template for a single invocation, pass `--from`:

```bash theme={null}
php artisan make:prompt code-reviewer --user --from=path/to/my-template.md
```

The `--from` option only affects the user prompt file. The system prompt always uses its own stub.

## Name normalisation

All prompt names are automatically converted to **kebab-case** for consistent directory naming. The conversion handles a variety of input formats:

| Input             | Result            |
| ----------------- | ----------------- |
| `MyPrompt`        | `my-prompt`       |
| `orderSummary`    | `order-summary`   |
| `snake_case_name` | `snake-case-name` |
| `LOUD_PROMPT`     | `loud-prompt`     |
| `My_Cool Prompt`  | `my-cool-prompt`  |
| `already-kebab`   | `already-kebab`   |

This normalisation applies to both the prompt name and any extra role names provided via `--role`.

## Configuration

The command respects the following values from `config/deck.php`:

| Key              | Default                    | Description                                         |
| ---------------- | -------------------------- | --------------------------------------------------- |
| `deck.path`      | `resource_path('prompts')` | Base directory where prompt structures are created. |
| `deck.extension` | `md`                       | File extension for generated prompt files.          |

See the full [Configuration](/getting-started/configuration) reference for all options.

## Examples

**Create a minimal prompt (system only):**

```bash theme={null}
php artisan make:prompt email-drafter
```

**Create a prompt with system + user files:**

```bash theme={null}
php artisan make:prompt email-drafter --user
```

**Create a prompt with system + multiple roles:**

```bash theme={null}
php artisan make:prompt email-drafter --role=assistant --role=reviewer
```

**Create a prompt with everything — user, roles, and a description:**

```bash theme={null}
php artisan make:prompt email-drafter -u --role=assistant --desc="Drafts professional emails"
```

**Fully interactive flow:**

```bash theme={null}
php artisan make:prompt
```

**Force-overwrite the latest version in CI:**

```bash theme={null}
php artisan make:prompt email-drafter --force
```

**Use a custom template for the user prompt:**

```bash theme={null}
php artisan make:prompt email-drafter --user --from=stubs/my-user.stub
```

### Success output

After successful creation, the command outputs a confirmation message:

```
Version 1 of the [email-drafter] prompt has been created successfully with the following roles: system, user, assistant.
```
