Skip to content

Language Reference

Complete specification of the PromptScript language.

File Structure

A PromptScript file (.prs) consists of:

# Comments start with #

@meta { ... }           # Required: Metadata
@inherit @path          # Optional: Inheritance
@use @path [as alias]   # Optional: Imports

@identity { ... }       # Content blocks
@context { ... }
@standards { ... }
@restrictions { ... }
@shortcuts { ... }
@params { ... }
@guards { ... }
@knowledge { ... }

@extend path { ... }    # Block modifications

Try in Playground

@meta Block (Required)

Every PromptScript file must have a @meta block defining metadata:

@meta {
  id: "project-id"           # Required: Unique identifier
  syntax: "1.0.0"            # Required: PromptScript syntax version (semver)

  # Optional fields
  org: "Company Name"
  team: "Frontend"
  tags: [frontend, react, typescript]
}

Try in Playground

Field Required Description
id Yes Unique identifier (string)
syntax Yes PromptScript syntax version (semver)
org No Organization name
team No Team name
tags No Array of tags
params No Parameter definitions for templates

Parameter Definitions

The params field defines parameters for parameterized inheritance:

@meta {
  id: "@stacks/typescript-lib"
  syntax: "1.0.0"
  params: {
    # Required string parameter
    projectName: string

    # Optional with default value
    runtime: string = "node18"

    # Optional parameter (no default, can be undefined)
    debug?: boolean

    # Enum parameter with constrained values
    testFramework: enum("vitest", "jest", "mocha") = "vitest"

    # Number parameter
    port: number = 3000
  }
}

Parameter Types:

Type Syntax Values
string name: string Any text
number count: number Integers and floats
boolean enabled: boolean true or false
enum mode: enum("a", "b") One of listed options

Parameter Modifiers:

Pattern Meaning
name: string Required, must be provided
name?: string Optional, can be omitted
name: string = "default" Optional with default value

@inherit Declaration

Single inheritance from another PromptScript file:

# From registry namespace
@inherit @company/frontend-team

# Relative path
@inherit ./parent

# With version constraint
@inherit @company/frontend-team@1.0.0

# With parameters (see Parameterized Inheritance below)
@inherit @stacks/react-app(projectName: "my-app", port: 3000)

Try in Playground

Single Inheritance

Each file can only have one @inherit declaration. Use @use for composition.

@use Declaration

Import and merge fragments for composition (like mixins):

# Import from registry - blocks are merged into current file
@use @core/guards/compliance

# Import with alias - blocks merged AND available for @extend
@use @core/guards/security as sec

# Import relative
@use ./fragments/logging

# Multiple imports - all merged in order
@use @core/standards/typescript
@use @core/restrictions/security
@use ./local-config

# With parameters (see Parameterized Inheritance below)
@use ./fragments/testing(framework: "vitest", coverage: 90) as testing

Try in Playground

Merge Behavior

When you use @use, all blocks from the imported file are merged into your file:

  • TextContent: Concatenated (source + target), with automatic deduplication of identical content
  • ObjectContent: Deep merged (target wins on key conflicts)
  • ArrayContent: Unique concatenation (preserves order, removes duplicates)
# Source: @core/guards/security
@restrictions {
  - "Never expose secrets"
}

# Target: ./project.prs
@use @core/guards/security

@restrictions {
  - "Follow OWASP guidelines"
}

# Result after merge:
# @restrictions contains both items (source first, then target)

Try in Playground

Alias for @extend Access

When you provide an alias, imported blocks are also stored with a prefix for use with @extend:

@use @core/typescript as ts

# Now you can extend imported blocks
@extend ts.standards {
  testing: { coverage: 90 }
}

Try in Playground

When to Use Alias

  • Without alias: Simple include/mixin behavior - blocks are merged directly
  • With alias: When you need to selectively extend specific imported blocks

Content Blocks

@identity

Core identity and persona definition:

@identity {
  """
  You are an expert frontend developer specializing in React.
  You write clean, maintainable, and well-tested code.
  """
}

Try in Playground

The identity block defines who the AI assistant should be.

Formatter Behavior:

Formatter How @identity is used
GitHub Included in the output as introductory text
Claude Placed at the beginning of CLAUDE.md
Cursor If it starts with "You are...", used as full intro; otherwise generates "You are working on {project}"
Antigravity Included in project description

Best Practice

Start your @identity with "You are..." for consistent output across all formatters. Multiline strings are automatically dedented to remove source indentation.

@context

Project context and environment:

@context {
  project: "Checkout Service"
  team: "Payments"
  environment: production

  """
  Additional context as text.
  This service handles payment processing for the e-commerce platform.
  """
}

Try in Playground

Supports both key-value properties and text content.

@standards

Coding standards and conventions using category-based arrays:

@standards {
  code: [
    "Use clean code principles",
    "Prefer hooks and composition patterns",
    "Write tests for all code (80% coverage minimum)",
    "Use vitest as the test framework"
  ]

  naming: [
    "Components: PascalCase",
    "Functions: camelCase",
    "Constants: UPPER_SNAKE_CASE"
  ]

  documentation: [
    "Document all public APIs",
    "Use JSDoc format"
  ]
}

Try in Playground

Standards are organized by category with each category containing an array of human-readable rules. You can use any category name (e.g., code, naming, security, api, documentation) - all keys are supported and will generate corresponding subsections in the output.

Backwards Compatibility

The errors key is automatically mapped to error-handling in the output for backwards compatibility.

@restrictions

Things the AI should never do:

@restrictions {
  - "Never expose API keys or secrets in code"
  - "Never commit sensitive data to version control"
  - "Always validate user input before processing"
  - "Never use deprecated APIs"
}

Try in Playground

Restrictions are concatenated during inheritance.

@shortcuts

Custom commands for quick actions:

@shortcuts {
  "/review": "Review code for quality and best practices"

  "/test": """
    Write unit tests using:
    - Vitest as the test runner
    - Testing Library for DOM testing
    - MSW for API mocking
  """

  "/refactor": "Suggest refactoring improvements for cleaner code"
}

Try in Playground

Shortcuts from child files override parent shortcuts with the same name.

Cursor Slash Commands (1.6+)

Multi-line shortcuts are automatically converted to executable slash commands:

Shortcut Type Output Location Behavior
Single-line .cursor/rules/project.mdc Listed as documentation in Commands section
Multi-line .cursor/commands/<name>.md Executable via /name in Cursor chat

Example:

@meta { id: "cursor-slash-commands" syntax: "1.0.0" }

@shortcuts {
  # Single-line → documentation only
  "/review": "Review code quality"

  # Multi-line → .cursor/commands/test.md
  "/test": """
    Write unit tests using:
    - Vitest as the test runner
    - AAA pattern (Arrange, Act, Assert)
  """
}

Try in Playground

Generates .cursor/commands/test.md:

Write unit tests using: - Vitest as the test runner - AAA pattern (Arrange, Act, Assert)

Using Cursor Commands

Type / in Cursor chat to see available commands, then select to execute.

GitHub Copilot Output

Shortcuts are handled differently based on their type:

Shortcut Type Output Location Behavior
Simple string copilot-instructions.md Listed in ## shortcuts section
Object without prompt: true copilot-instructions.md Listed in ## shortcuts section (uses description)
Object with prompt: true .github/prompts/<name>.prompt.md Generates separate prompt file

GitHub Copilot Prompts

To generate .github/prompts/*.prompt.md files for GitHub Copilot, use the object syntax with prompt: true:

@meta { id: "github-prompts-example" syntax: "1.0.0" }

@shortcuts {
  # Simple string → listed in ## shortcuts section
  "/review": "Review code for quality"

  # Object with prompt: true → generates .github/prompts/test.prompt.md
  "/test": {
    prompt: true
    description: "Write unit tests"
    content: """
      Write unit tests using:
      - Vitest as the test runner
      - AAA pattern (Arrange, Act, Assert)
    """
  }

  # Agent mode prompt with tools
  "/deploy": {
    prompt: true
    description: "Deploy to production"
    mode: agent
    tools: [run_terminal, read_file]
    content: """
      Deploy the application to production:
      1. Run tests
      2. Build the project
      3. Deploy to staging
      4. Run smoke tests
      5. Deploy to production
    """
  }
}

Try in Playground

Property Type Required Description
prompt boolean Yes Must be true to generate a prompt file
description string Yes Shown in prompt picker UI
content string Yes The prompt instructions
mode string No Set to "agent" for agentic prompts
tools string[] No Tools available in agent mode

Output Mode Required

Prompt files are only generated when using version: multifile or version: full in your target configuration:

```yaml
targets:
  - github:
      version: multifile  # Enables .github/prompts/*.prompt.md
```

Generated file (.github/prompts/test.prompt.md):

---
description: 'Write unit tests'
---

Write unit tests using:

- Vitest as the test runner
- AAA pattern (Arrange, Act, Assert)

Antigravity Workflows

For Antigravity, shortcuts with steps property generate workflow files:

@shortcuts {
  "/deploy": {
    description: "Deploy the application"
    steps: ["Build the project", "Run tests", "Deploy to staging"]
  }
}

Try in Playground

Property Type Description
description string Workflow description
steps string[] Ordered list of workflow steps

Generates .agent/workflows/deploy.md with numbered steps.

@params

Configurable parameters:

@params {
  strictness: range(1..5) = 3
  format?: enum("json", "text", "markdown") = "text"
  verbose: boolean = false
}

Try in Playground

Syntax Description
name: type Required parameter
name?: type Optional parameter
= value Default value

@guards

Runtime validation rules and file targeting:

@guards {
  maxFileSize: 1000
  allowedLanguages: [typescript, javascript, css]

  # Glob patterns for file-specific rules (used by multifile formatters)
  globs: ["**/*.ts", "**/*.tsx"]

  """
  Additional guard rules as text.
  """
}

Try in Playground

The globs property is used by multifile formatters (GitHub, Claude, Cursor) to generate path-specific instruction files.

GitHub Copilot applyTo Integration

When using version: multifile or version: full for GitHub Copilot, the globs patterns generate separate instruction files with applyTo frontmatter:

@meta { id: "guards-applyto-example" syntax: "1.0.0" }

@guards {
  globs: ["**/*.ts", "**/*.tsx", "**/*.spec.ts", "**/*.test.ts"]
}

@standards {
  typescript: [
    "Use strict TypeScript with no any types",
    "Prefer interfaces over type aliases"
  ]

  testing: [
    "Use Vitest for unit tests",
    "Follow AAA pattern (Arrange, Act, Assert)"
  ]
}

Try in Playground

This generates:

.github/instructions/typescript.instructions.md:

---
applyTo:
  - '**/*.ts'
  - '**/*.tsx'
  - '**/*.spec.ts'
  - '**/*.test.ts'
---

# TypeScript-specific coding rules

.github/instructions/testing.instructions.md:

---
applyTo:
  - '**/*.spec.ts'
  - '**/*.test.ts'
---

# Testing-specific rules and patterns

Follow project testing conventions.

Version Required

Path-specific instruction files are only generated with version: multifile or version: full:

```yaml
targets:
  - github:
      version: multifile
```

@skills

Define reusable skills that AI assistants can invoke:

@meta { id: "skills-example" syntax: "1.0.0" }

@skills {
  commit: {
    description: "Create git commits"
    disableModelInvocation: true
    context: "fork"
    agent: "general-purpose"
    allowedTools: ["Bash", "Read", "Write"]
    content: """
      When creating commits:
      1. Use conventional commit format
      2. Include Co-Authored-By trailer
      3. Never amend existing commits
    """
  }

  review: {
    description: "Review code changes"
    userInvocable: true
    content: """
      Perform thorough code review checking:
      - Type safety
      - Error handling
      - Security vulnerabilities
    """
  }
}

Try in Playground

Property Type Formatter Description
description string All Human-readable description
content string All Detailed skill instructions
disableModelInvocation boolean GitHub Prevent model from auto-invoking skill
userInvocable boolean Claude Allow user to manually invoke skill
context string Claude Context mode: "fork" or "inherit"
agent string Claude Agent type: "general-purpose", etc.
allowedTools string[] Claude Tools the skill can use

Skills are output differently based on the formatter:

GitHub Output (.github/skills/commit/SKILL.md, version: full):

---
name: 'commit'
description: 'Create git commits'
disable-model-invocation: true
---

When creating commits:

1. Use conventional commit format
2. Include Co-Authored-By trailer
3. Never amend existing commits

Claude Output (.claude/skills/commit/SKILL.md, version: full):

---
name: 'commit'
description: 'Create git commits'
context: fork
agent: general-purpose
allowed-tools:
  - Bash
  - Read
  - Write
---

When creating commits:

1. Use conventional commit format
2. Include Co-Authored-By trailer
3. Never amend existing commits

@agents

Define specialized AI subagents for GitHub Copilot and Claude Code:

@meta { id: "agents-example" syntax: "1.0.0" }

@agents {
  code-reviewer: {
    description: "Reviews code for quality and best practices"
    tools: ["Read", "Grep", "Glob", "Bash"]
    model: "sonnet"
    content: """
      You are a senior code reviewer ensuring high standards.

      When invoked:
      1. Run git diff to see recent changes
      2. Focus on modified files
      3. Begin review immediately

      Review checklist:
      - Code is clear and readable
      - Functions and variables are well-named
      - No duplicated code
      - Proper error handling
    """
  }

  debugger: {
    description: "Debugging specialist for errors and test failures"
    tools: ["Read", "Edit", "Bash", "Grep", "Glob"]
    disallowedTools: ["Write"]
    model: "inherit"
    permissionMode: "acceptEdits"
    skills: ["error-handling", "testing-patterns"]
    content: """
      You are an expert debugger specializing in root cause analysis.
    """
  }
}

Try in Playground

Property Type Required Description
description string Yes When the agent should be invoked
content string Yes System prompt for the subagent
tools string[] No Allowed tools (inherits all if omitted)
model string No AI model to use (platform-specific values)
disallowedTools string[] No Tools to deny (Claude only)
permissionMode string No default, acceptEdits, dontAsk, bypassPermissions, plan (Claude only)
skills string[] No Skills to preload into subagent context (Claude only)

Agents output by platform:

GitHub Output (.github/agents/code-reviewer.md, version: full)

Supports: name, description, tools, model. Tool and model names are automatically mapped to GitHub Copilot's format:

  • Tools: Readread, Grep/Globsearch, Bashexecute
  • Models: sonnetClaude Sonnet 4.5, opusClaude Opus 4.5, haikuClaude Haiku 4.5
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: ['read', 'search', 'execute']
model: Claude Sonnet 4.5
---

You are a senior code reviewer ensuring high standards.

When invoked:

1. Run git diff to see recent changes
2. Focus on modified files
3. Begin review immediately

Review checklist:

- Code is clear and readable
- Functions and variables are well-named
- No duplicated code
- Proper error handling

Claude Output (.claude/agents/code-reviewer.md, version: full)

Supports all properties including disallowedTools, permissionMode, skills:

---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Grep, Glob, Bash
model: sonnet
---

You are a senior code reviewer ensuring high standards.

When invoked:

1. Run git diff to see recent changes
2. Focus on modified files
3. Begin review immediately

Review checklist:

- Code is clear and readable
- Functions and variables are well-named
- No duplicated code
- Proper error handling

Hooks Support

Claude Code agent hooks (PreToolUse, PostToolUse, Stop) are planned but not yet implemented. See Roadmap.

@local

Private instructions not committed to version control:

@local {
  """
  Private development notes and local configuration.
  This content is not committed to git.

  Local environment setup:
  - API keys are in .env.local
  - Use staging backend at localhost:8080
  """
}

Try in Playground

Or with key-value properties:

@local {
  apiEndpoint: "http://localhost:8080"
  debugMode: true
  customPaths: ["/tmp/dev" "/var/local"]

  """
  Additional local notes...
  """
}

Try in Playground

@local Output

The @local block generates CLAUDE.local.md when using the Claude formatter with version: full. This file should be added to .gitignore.

@knowledge

Reference documentation and knowledge:

@knowledge {
  """
  ## API Reference

  ### Authentication
  - POST /api/auth/login - User login
  - POST /api/auth/logout - User logout

  ### Users
  - GET /api/users - List users
  - GET /api/users/:id - Get user by ID

  ## Architecture Notes

  The service follows a clean architecture pattern with:
  - Controllers for HTTP handling
  - Services for business logic
  - Repositories for data access
  """
}

Try in Playground

@extend Block

Modify inherited or existing blocks:

# Extend a top-level block
@extend identity {
  """
  Additional identity information.
  """
}

# Extend a nested path
@extend standards.code {
  frameworks: [react vue]
}

# Extend multiple levels deep
@extend standards.code.testing {
  e2e: true
  coverage: 90
}

Try in Playground

Values

Primitive Types

Type Examples
String "hello", 'world'
Number 42, 3.14, -10
Boolean true, false
Null null

Strings

PromptScript supports two string syntaxes:

Single-line Strings

Use double or single quotes for short, single-line values:

@shortcuts {
  "/review": "Review code for quality and best practices"
  "/help": 'Show available commands'
}

Try in Playground

Multi-line Strings

Use triple quotes (""") for content that spans multiple lines:

@shortcuts {
  "/test": """
    Write unit tests using:
    - Vitest as the test runner
    - AAA pattern (Arrange, Act, Assert)
    - Target >90% coverage
  """
}

Try in Playground

Multi-line strings:

  • Preserve line breaks and formatting
  • Are ideal for lists, instructions, and documentation
  • Can be used anywhere a string is expected

When to Use Which

Content Type Recommended Syntax
Short description (1 line) "..." or '...'
Multiple lines, lists, steps """..."""
Code examples, documentation """..."""

Both forms are semantically equivalent - choose based on readability.

Example: Mixed Usage

@shortcuts {
  # Single-line - simple description
  "/review": "Review code for quality and best practices"

  # Multi-line - detailed instructions
  "/deploy": """
    Deploy to production:
    1. Run tests: pnpm test
    2. Build: pnpm build
    3. Deploy: pnpm deploy:prod
  """

  # Single-line - short command
  "/format": "Run prettier on all files"
}

Try in Playground

Identifiers

Bare words are treated as strings:

@meta {
  team: Frontend  # Same as "Frontend"
}

Try in Playground

Arrays

tags: [frontend react typescript]
patterns: ["hooks" "composition" "render props"]
numbers: [1 2 3]

Try in Playground

Objects

code: {
  style: "functional"
  testing: {
    required: true
    coverage: 80
  }
}

Try in Playground

Template Expressions

Use {{variable}} syntax to reference template parameters:

@meta {
  id: "template-example"
  syntax: "1.0.0"
  params: {
    projectName: string
    port: number = 3000
  }
}

@identity {
  """
  You are working on {{projectName}}.
  """
}

@context {
  project: {{projectName}}
  devServer: "http://localhost:{{port}}"
}

Template expressions are resolved during inheritance resolution when parameters are bound.

Valid Variable Names:

  • Must start with a letter or underscore
  • Can contain letters, numbers, and underscores
  • Examples: {{name}}, {{projectName}}, {{_internal}}

Template vs Environment Variables:

Syntax Resolved Purpose
{{var}} At resolve time Template parameters
${VAR} At parse time Environment variables
# Environment variable - from system at parse time
apiUrl: ${API_URL:-https://api.example.com}

# Template variable - from @inherit params at resolve time
project: {{projectName}}

Type Expressions

Range

Numeric range constraint:

strictness: range(1..10)
verbosity: range(0..5) = 2

Try in Playground

Enum

String enumeration:

format: enum("json", "text", "markdown")
level: enum("debug", "info", "warn", "error") = "info"

Try in Playground

Comments

Single-line comments with #:

# This is a comment
@meta {
  id: "project"  # Inline comment
  syntax: "1.0.0"
}

Try in Playground

Path References

Path syntax for imports and inheritance:

Format Example Description
Namespaced @company/team Registry namespace
Versioned @company/team@1.0.0 With version
Relative ./parent Relative path
Nested @company/guards/security Nested path

Reserved Words

The following are reserved and cannot be used as identifiers:

Literals:

  • true, false, null

Type expressions (for @params):

  • range, enum

Directives:

  • meta, inherit, use, extend, as

Block names:

  • identity, context, standards, restrictions
  • knowledge, shortcuts, guards, params
  • skills, agents, local
  • workflows, prompts (internal, not user-facing)

Internal Block Types

The names workflows and prompts are reserved but not user-facing blocks. Workflow files are generated from @shortcuts with steps property (Antigravity). Prompt files are generated from @shortcuts with prompt: true (GitHub Copilot).

File Extensions

Extension Description
.prs PromptScript source file
.promptscript Alternative extension (supported)

Known Issues & Gotchas

Multiline Strings in Objects

Multiline strings ("""...""") cannot be used as "loose" content inside an object with curly braces. They must always be assigned to a key.

❌ Invalid:

@standards {
  diagrams: {
    format: "Mermaid"
    types: [flowchart sequence]
    """
    Example:
    ```
<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAJxYasAJhmqC4AAmAAdVuPGCIGAObVScRJJly5YZtRLYNUkAFkY+jBEHGt2rAE808DcjBRmAd0Y4RWcXBgARwBXTkYYAF1bORsQG1ltAFFiMlhEEABfCIZOLGp7fCJSchgqWhAGADdzOAg2fABGTKA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->
mermaid
    flowchart LR
      A[Input] --> B[Process] --> C[Output]
    ```
    """
  }
}

This will cause a parse error:

Expecting token of type --> RBrace <-- but found --> '"""...

✅ Valid - assign to a key:

@standards {
  diagrams: {
    format: "Mermaid"
    types: [flowchart sequence]
    example: """
      ```
<!-- playground-link-start -->
<a href="https://getpromptscript.dev/playground/?s=N4IgZglgNgpgziAXAbVABwIYBcAWSQwAeGAtmrAHRoBOCANCAMYD2AdljO-gAJxYasAJhmqC4AAmAAdVuPGCIGAObVScRJJly5YZtRLYNUkAFkY+jBEHGt2rAE808DcjBRmAd0Y4RWcXBgARwBXTkYYAF1bOSJSchgjEBsQEABfCIZOLGp7fFiyShp6EAA3czgINnwARjSgA" target="_blank" rel="noopener noreferrer">
  <img src="https://img.shields.io/badge/Try_in-Playground-blue?style=flat-square" alt="Try in Playground" />
</a>
<!-- playground-link-end -->
mermaid
      flowchart LR
        A[Input] --> B[Process] --> C[Output]
      ```
    """
  }
}

✅ Valid - use at block level:

@knowledge {
  """
  Multiline content works directly in blocks
  without needing a key assignment.
  """
}

Try in Playground

Rule of Thumb

Inside { } braces, everything needs a key. Multiline strings without keys only work directly inside blocks like @identity { ... } or @knowledge { ... }.

Environment Variable Interpolation

String values can reference environment variables for dynamic configuration:

@context {
  api-endpoint: "${API_ENDPOINT}"
  environment: "${NODE_ENV:-development}"
}

Try in Playground

Syntax

Pattern Description
${VAR} Substitute with variable value
${VAR:-default} Substitute with variable or default

Examples

@meta {
  id: "env-vars-example"
  syntax: "1.0.0"
}

@context {
  project: "My App - ${PROJECT_NAME:-default}"

  """
  Running in ${NODE_ENV:-development} mode.
  API Key: ${API_KEY}
  """
}

Try in Playground

Missing Variables

If a variable is not set and no default is provided:

- An empty string is substituted
- A warning is logged to the console

This follows Linux shell behavior for unset variables.

Best Practices

  1. Always provide defaults for non-sensitive values
  2. Never commit secrets - use environment variables for API keys
  3. Document required variables in your project README