Skip to main content

API and Programmatic Usage

For automated workflows, CI/CD pipelines, and custom applications, you can deploy security prompts programmatically through LLM provider APIs. This gives you full control over prompt versioning, model selection, and runtime behavior.

OpenAI API

Pass the security prompt as the system message in the Chat Completions API:

from openai import OpenAI

client = OpenAI()

# Load the security prompt from a file
with open("prompts/node-security.md") as f:
security_prompt = f.read()

response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": security_prompt},
{"role": "user", "content": "Write an Express.js login endpoint"}
]
)

print(response.choices[0].message.content)

With the Responses API

response = client.responses.create(
model="gpt-4o",
instructions=security_prompt,
input="Write an Express.js login endpoint"
)

print(response.output_text)

Anthropic API

Pass the security prompt as the system parameter:

import anthropic

client = anthropic.Anthropic()

with open("prompts/python-security.md") as f:
security_prompt = f.read()

message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
system=security_prompt,
messages=[
{"role": "user", "content": "Write a Django authentication view"}
]
)

print(message.content[0].text)

Google Gemini API

Pass the security prompt as system_instruction:

from google import genai

client = genai.Client()

with open("prompts/java-security.md") as f:
security_prompt = f.read()

response = client.models.generate_content(
model="gemini-2.0-flash",
config=genai.types.GenerateContentConfig(
system_instruction=security_prompt
),
contents="Write a Spring Boot REST controller with authentication"
)

print(response.text)

OpenRouter

OpenRouter provides a unified API that routes to multiple model providers. It uses the OpenAI-compatible format:

from openai import OpenAI

client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="your-openrouter-key"
)

with open("prompts/go-security.md") as f:
security_prompt = f.read()

response = client.chat.completions.create(
model="google/gemini-2.0-flash-001",
messages=[
{"role": "system", "content": security_prompt},
{"role": "user", "content": "Write an HTTP handler with input validation in Go"}
]
)

print(response.choices[0].message.content)

Tips

  • OpenRouter lets you switch models without changing your code — just change the model parameter
  • Use free models like google/gemini-2.0-flash-001 for testing and development
  • The same system prompt format works across all OpenRouter-supported models

Loading Prompts from Files

All the examples above load the prompt from a file at runtime. This is the recommended pattern because it:

  • Keeps prompt content out of your application code
  • Makes updates simple — replace the file, restart the service
  • Enables version control of prompt files alongside code
  • Supports environment-specific prompts (dev, staging, production)

Directory Structure

your-project/
├── prompts/
│ ├── node-security.md
│ ├── python-security.md
│ └── VERSION
├── src/
│ └── ...
└── ...

Loading with Error Handling

import os

def load_prompt(framework: str) -> str:
prompt_path = os.path.join("prompts", f"{framework}-security.md")
with open(prompt_path) as f:
return f.read()

# Usage
security_prompt = load_prompt("node")

Dynamic Prompt Selection

If your application supports multiple frameworks, select the appropriate prompt at runtime:

PROMPT_MAP = {
"node": "prompts/node-security.md",
"python": "prompts/python-security.md",
"java": "prompts/java-security.md",
"go": "prompts/go-security.md",
}

def get_security_prompt(framework: str) -> str:
path = PROMPT_MAP.get(framework)
if not path:
raise ValueError(f"No security prompt for framework: {framework}")
with open(path) as f:
return f.read()

This is useful for platforms that serve multiple teams or projects using different technology stacks.

Combining Security and Validation Prompts

You can layer a code security prompt with a validation prompt for defense in depth:

with open("prompts/node-security.md") as f:
code_security = f.read()

with open("prompts/output-guard.md") as f:
output_guard = f.read()

# Use the security prompt for code generation
code_response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": code_security},
{"role": "user", "content": "Write a file upload handler"}
]
)

generated_code = code_response.choices[0].message.content

# Validate the output with the guard prompt
guard_response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": output_guard},
{"role": "user", "content": f"Review this code for security issues:\n\n{generated_code}"}
]
)

CI/CD Integration

Embed security prompts into your CI pipeline to review code changes automatically:

# .github/workflows/security-review.yml
name: AI Security Review
on:
pull_request:
paths: ['src/**']

jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get changed files
id: changes
run: |
echo "files=$(git diff --name-only origin/main...HEAD -- src/ | tr '\n' ' ')" >> $GITHUB_OUTPUT
- name: Run security review
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
python scripts/security-review.py ${{ steps.changes.outputs.files }}

Where scripts/security-review.py loads the appropriate security prompt and sends each changed file for review.

Tips

  • Store API keys in your CI/CD platform's secrets manager
  • Use a fast, inexpensive model for CI reviews (e.g., gpt-4o-mini or gemini-2.0-flash)
  • Set a timeout on the review step to prevent pipeline hangs
  • Output review results as PR comments using the GitHub API