CI/CD Integration¶
PromptScript creates prompt-as-code for your AI instructions. Like any code, it should be validated and tested in your Continuous Integration (CI) pipeline.
Overview¶
Integrating PromptScript into CI/CD provides:
- Syntax Validation - Catch
.prsfile errors before merge - Drift Detection - Ensure compiled outputs are up-to-date
- Registry Sync - Validate against latest registry standards
- Change Tracking - Only run on relevant file changes
flowchart LR
subgraph CI["CI Pipeline"]
checkout["Checkout"]
install["Install CLI"]
validate["prs validate"]
compile["prs compile"]
diff["Check Drift"]
end
checkout --> install --> validate --> compile --> diff
validate -->|"Errors"| fail["❌ Fail"]
diff -->|"Uncommitted changes"| fail
diff -->|"All synced"| pass["✅ Pass"] Key Commands for CI¶
| Command | Purpose | Exit Code |
|---|---|---|
prs validate | Validate syntax and structure | 0=pass, 1=error, 2=warning (with --strict) |
prs validate --strict | Treat warnings as errors | 0=pass, 1=error, 2=warning |
prs validate --format json | JSON output for parsing | Same as above |
prs compile | Compile to all targets | 0=success, 1=error |
prs compile --dry-run | Preview without writing | 0=success, 1=error |
prs check | Check config and dependencies | 0=healthy, 1=issues |
prs diff --all | Show uncommitted changes | Always 0 |
GitHub Actions¶
Basic Validation¶
Create .github/workflows/promptscript.yml:
name: PromptScript
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install PromptScript CLI
run: npm install -g @promptscript/cli
- name: Validate PromptScript files
run: prs validate --strict
- name: Compile and verify
run: prs compile
Drift Detection¶
Ensure compiled files are always in sync with source .prs files:
name: PromptScript Drift Detection
on:
push:
paths:
- '.promptscript/**'
- 'promptscript.yaml'
pull_request:
paths:
- '.promptscript/**'
- 'promptscript.yaml'
jobs:
check-drift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install PromptScript CLI
run: npm install -g @promptscript/cli
- name: Validate
run: prs validate --strict
- name: Compile
run: prs compile
- name: Check for drift
run: |
if ! git diff --quiet; then
echo "::error::Compiled files are out of sync with source."
echo "::error::Run 'prs compile' locally and commit the changes."
git diff --stat
exit 1
fi
echo "✅ All compiled files are in sync"
With Private Registry¶
For projects using a private Git registry:
name: PromptScript with Registry
on:
push:
branches: [main]
pull_request:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install PromptScript CLI
run: npm install -g @promptscript/cli
- name: Pull registry
run: prs pull
env:
GITHUB_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Validate
run: prs validate --strict
env:
GITHUB_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Compile
run: prs compile
env:
GITHUB_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
- name: Check drift
run: |
if ! git diff --quiet; then
echo "::error::Compiled files are out of date"
exit 1
fi
Change Detection with Path Filters¶
Only run validation when PromptScript files change:
name: PromptScript (Optimized)
on:
push:
paths:
- '.promptscript/**/*.prs'
- 'promptscript.yaml'
- '.github/workflows/promptscript.yml'
pull_request:
paths:
- '.promptscript/**/*.prs'
- 'promptscript.yaml'
- '.github/workflows/promptscript.yml'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install PromptScript CLI
run: npm install -g @promptscript/cli
- name: Validate and compile
run: |
prs validate --strict
prs compile
- name: Verify no drift
run: git diff --exit-code
Matrix Build for Multiple Projects¶
For monorepos with multiple PromptScript projects:
name: PromptScript Monorepo
on:
push:
branches: [main]
pull_request:
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
projects: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
frontend:
- 'apps/frontend/.promptscript/**'
- 'apps/frontend/promptscript.yaml'
backend:
- 'apps/backend/.promptscript/**'
- 'apps/backend/promptscript.yaml'
shared:
- 'packages/shared/.promptscript/**'
- 'packages/shared/promptscript.yaml'
validate:
needs: detect-changes
if: ${{ needs.detect-changes.outputs.projects != '[]' }}
runs-on: ubuntu-latest
strategy:
matrix:
project: ${{ fromJson(needs.detect-changes.outputs.projects) }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install PromptScript CLI
run: npm install -g @promptscript/cli
- name: Validate ${{ matrix.project }}
working-directory: apps/${{ matrix.project }}
run: |
prs validate --strict
prs compile
git diff --exit-code
GitLab CI/CD¶
Basic Pipeline¶
Add to .gitlab-ci.yml:
stages:
- validate
promptscript:
stage: validate
image: node:20-alpine
before_script:
- npm install -g @promptscript/cli
script:
- prs validate --strict
- prs compile
- |
if ! git diff --quiet; then
echo "Error: Compiled files are out of sync"
git diff --stat
exit 1
fi
rules:
- changes:
- .promptscript/**/*
- promptscript.yaml
With Private Registry¶
stages:
- validate
promptscript:
stage: validate
image: node:20-alpine
variables:
GITHUB_TOKEN: $REGISTRY_TOKEN
before_script:
- npm install -g @promptscript/cli
script:
- prs pull
- prs validate --strict
- prs compile
rules:
- changes:
- .promptscript/**/*
- promptscript.yaml
With Caching¶
stages:
- validate
promptscript:
stage: validate
image: node:20-alpine
cache:
key: promptscript-${CI_COMMIT_REF_SLUG}
paths:
- .promptscript/.cache/
before_script:
- npm install -g @promptscript/cli
script:
- prs validate --strict
- prs compile
- git diff --exit-code
rules:
- changes:
- .promptscript/**/*
- promptscript.yaml
Merge Request Validation¶
stages:
- validate
- report
promptscript:validate:
stage: validate
image: node:20-alpine
before_script:
- npm install -g @promptscript/cli
script:
- prs validate --strict
- prs compile
artifacts:
paths:
- .github/copilot-instructions.md
- CLAUDE.md
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- .promptscript/**/*
- promptscript.yaml
promptscript:drift:
stage: report
image: node:20-alpine
needs: [promptscript:validate]
script:
- |
if ! git diff --quiet; then
echo "⚠️ Compiled files differ from source"
git diff --stat
exit 1
fi
echo "✅ All files in sync"
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
Azure DevOps Pipelines¶
PR Triggers for Azure Repos
YAML pr: triggers only work for GitHub and Bitbucket repositories. For Azure Repos, configure PR validation through branch policies in Project Settings → Repos → Branches.
Basic Pipeline¶
Create azure-pipelines.yml:
trigger:
branches:
include:
- main
paths:
include:
- .promptscript/**
- promptscript.yaml
pr:
branches:
include:
- main
paths:
include:
- .promptscript/**
- promptscript.yaml
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
displayName: 'Setup Node.js'
- script: npm install -g @promptscript/cli
displayName: 'Install PromptScript CLI'
- script: prs validate --strict
displayName: 'Validate PromptScript files'
- script: prs compile
displayName: 'Compile PromptScript'
- script: |
if ! git diff --quiet; then
echo "##vso[task.logissue type=error]Compiled files are out of sync"
git diff --stat
exit 1
fi
displayName: 'Check for drift'
With Variable Groups (Private Registry)¶
trigger:
branches:
include:
- main
variables:
- group: promptscript-secrets
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
displayName: 'Setup Node.js'
- script: npm install -g @promptscript/cli
displayName: 'Install PromptScript CLI'
- script: prs pull
displayName: 'Pull registry updates'
env:
GITHUB_TOKEN: $(REGISTRY_TOKEN)
- script: prs validate --strict
displayName: 'Validate PromptScript files'
env:
GITHUB_TOKEN: $(REGISTRY_TOKEN)
- script: prs compile
displayName: 'Compile PromptScript'
env:
GITHUB_TOKEN: $(REGISTRY_TOKEN)
- script: |
if ! git diff --quiet; then
echo "##vso[task.logissue type=error]Compiled files are out of sync. Run 'prs compile' locally."
exit 1
fi
displayName: 'Check for drift'
Multi-Stage Pipeline¶
trigger:
branches:
include:
- main
- develop
paths:
include:
- .promptscript/**
- promptscript.yaml
stages:
- stage: Validate
displayName: 'Validate PromptScript'
jobs:
- job: Validate
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
- script: npm install -g @promptscript/cli
displayName: 'Install CLI'
- script: prs validate --strict --format json > $(Build.ArtifactStagingDirectory)/validation.json
displayName: 'Validate'
- publish: $(Build.ArtifactStagingDirectory)/validation.json
artifact: validation-report
displayName: 'Publish validation report'
- stage: Compile
displayName: 'Compile & Check Drift'
dependsOn: Validate
jobs:
- job: Compile
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
- script: npm install -g @promptscript/cli
displayName: 'Install CLI'
- script: prs compile
displayName: 'Compile'
- script: |
if ! git diff --quiet; then
echo "##vso[task.logissue type=error]Drift detected"
exit 1
fi
displayName: 'Check drift'
Jenkins¶
Declarative Pipeline¶
Create Jenkinsfile:
pipeline {
agent {
docker {
image 'node:20-alpine'
}
}
triggers {
pollSCM('H/5 * * * *')
}
stages {
stage('Setup') {
steps {
sh 'npm install -g @promptscript/cli'
}
}
stage('Validate') {
steps {
sh 'prs validate --strict'
}
}
stage('Compile') {
steps {
sh 'prs compile'
}
}
stage('Check Drift') {
steps {
sh '''
if ! git diff --quiet; then
echo "ERROR: Compiled files are out of sync"
git diff --stat
exit 1
fi
'''
}
}
}
post {
failure {
echo 'PromptScript validation failed!'
}
success {
echo 'PromptScript validation passed!'
}
}
}
With Credentials (Private Registry)¶
pipeline {
agent {
docker {
image 'node:20-alpine'
}
}
environment {
GITHUB_TOKEN = credentials('registry-token')
}
stages {
stage('Setup') {
steps {
sh 'npm install -g @promptscript/cli'
}
}
stage('Pull Registry') {
steps {
sh 'prs pull'
}
}
stage('Validate') {
steps {
sh 'prs validate --strict'
}
}
stage('Compile') {
steps {
sh 'prs compile'
}
}
stage('Check Drift') {
steps {
sh 'git diff --exit-code'
}
}
}
}
Change Detection with changeset¶
pipeline {
agent {
docker {
image 'node:20-alpine'
}
}
stages {
stage('Check Changes') {
steps {
script {
def changes = currentBuild.changeSets.collectMany { it.items }
.collectMany { it.affectedFiles }
.collect { it.path }
env.HAS_PRS_CHANGES = changes.any {
it.startsWith('.promptscript/') || it == 'promptscript.yaml'
}.toString()
}
}
}
stage('Validate PromptScript') {
when {
expression { env.HAS_PRS_CHANGES == 'true' }
}
steps {
sh 'npm install -g @promptscript/cli'
sh 'prs validate --strict'
sh 'prs compile'
sh 'git diff --exit-code'
}
}
}
}
CircleCI¶
Basic Configuration¶
Create .circleci/config.yml:
version: 2.1
jobs:
promptscript:
docker:
- image: cimg/node:20.0
steps:
- checkout
- run:
name: Install PromptScript CLI
command: npm install -g @promptscript/cli
- run:
name: Validate
command: prs validate --strict
- run:
name: Compile
command: prs compile
- run:
name: Check drift
command: |
if ! git diff --quiet; then
echo "Compiled files are out of sync"
exit 1
fi
workflows:
validate:
jobs:
- promptscript:
filters:
branches:
only:
- main
- /feature\/.*/
With Path Filtering¶
version: 2.1
setup: true
orbs:
path-filtering: circleci/path-filtering@1
workflows:
setup-workflow:
jobs:
- path-filtering/filter:
mapping: |
.promptscript/.* promptscript true
promptscript.yaml promptscript true
base-revision: main
config-path: .circleci/continue-config.yml
Create .circleci/continue-config.yml:
version: 2.1
parameters:
promptscript:
type: boolean
default: false
jobs:
validate-promptscript:
docker:
- image: cimg/node:20.0
steps:
- checkout
- run: npm install -g @promptscript/cli
- run: prs validate --strict
- run: prs compile
- run: git diff --exit-code
workflows:
promptscript:
when: << pipeline.parameters.promptscript >>
jobs:
- validate-promptscript
Docker-based CI¶
For consistent environments across all CI systems, use the official Docker image. This eliminates Node.js version mismatches and simplifies configuration.
# Any CI system with Docker support
image: ghcr.io/mrwogu/promptscript:latest
steps:
- prs validate --strict
- prs compile
- git diff --exit-code
See the Docker Guide for complete examples including:
- GitHub Actions with container jobs
- GitLab CI with Docker image
- Jenkins with Docker agent
- Azure DevOps with container jobs
Pre-commit Hooks¶
Catch issues before they reach CI with local pre-commit hooks.
Using Husky¶
- Install dependencies:
- Initialize husky:
- Edit
.husky/pre-commit(created by init):
# Only run if .prs files are staged
if git diff --cached --name-only | grep -qE '\.prs$|promptscript\.yaml$'; then
echo "🔍 Validating PromptScript files..."
npx prs validate --strict
npx prs compile
# Check if compile changed any files
if ! git diff --quiet; then
echo "⚠️ Compiled files changed. Please stage the changes."
git diff --stat
exit 1
fi
fi
Using pre-commit Framework¶
Create .pre-commit-config.yaml:
repos:
- repo: local
hooks:
- id: promptscript-validate
name: Validate PromptScript
entry: npx prs validate --strict
language: system
files: '\.prs$|promptscript\.yaml$'
pass_filenames: false
- id: promptscript-compile
name: Compile PromptScript
entry: bash -c 'npx prs compile && git diff --exit-code'
language: system
files: '\.prs$|promptscript\.yaml$'
pass_filenames: false
Install the hooks:
Using lint-staged¶
For projects already using lint-staged:
{
"lint-staged": {
"*.prs": ["prs validate --strict"],
"promptscript.yaml": ["prs validate --strict"]
}
}
Best Practices¶
1. Use Strict Mode in CI¶
Always use --strict flag in CI to catch warnings early:
2. Implement Drift Detection¶
Ensure compiled outputs match source files:
3. Use Path Filters¶
Only run PromptScript validation when relevant files change to save CI time:
4. Cache Registry¶
For projects with remote registries, cache pulled files:
# GitHub Actions
- uses: actions/cache@v4
with:
path: ~/.cache/promptscript
key: promptscript-registry-${{ hashFiles('promptscript.yaml') }}
5. Fail Fast¶
Place validation early in your pipeline to fail quickly:
6. JSON Output for Integration¶
Use JSON output for programmatic processing:
7. Environment Variables¶
Use environment variables for CI configuration:
| Variable | Purpose |
|---|---|
GITHUB_TOKEN | Registry authentication |
PROMPTSCRIPT_VERBOSE | Enable verbose output |
NO_COLOR | Disable colored output |
Troubleshooting¶
Common CI Issues¶
Error: Config file not found
Ensure promptscript.yaml exists in the repository root or specify path with --config.
Error: Registry authentication failed
Check that GITHUB_TOKEN or equivalent secret is set and has read access to the registry repository.
Error: Drift detected
Run prs compile locally and commit the generated files.
Error: Node.js version mismatch
PromptScript requires Node.js 20+. Update your CI configuration to use node:20 or higher.
Debug Mode¶
Enable verbose output for troubleshooting: