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
modelparameter - Use free models like
google/gemini-2.0-flash-001for 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-miniorgemini-2.0-flash) - Set a timeout on the review step to prevent pipeline hangs
- Output review results as PR comments using the GitHub API