Prompt Allowlist Policy
The prompt-allowlist policy category constrains which named system-prompt templates are permitted for a run. Cross-references the prompt-management system (Prompt rows).
Use case: enterprise compliance where prompts are vetted assets. Tenants pin to a curated set of prompt names; ad-hoc prompts get flagged.
Rules
| Rule | Type | Default | Description |
|---|---|---|---|
allowed_prompts | string[] | [] | Allowlist of template names. Empty = all allowed |
blocked_prompts | string[] | [] | Always-deny list. Wins over allowlist |
action_on_violation | string | block | Action on violation: block or warn |
How It Works
The handler runs at before_workflow only -- the prompt template is known at run start. after_workflow is a no-op.
Reads the prompt name from context.prompt_name first, then falls back to context.metadata["prompt_name"]. Absent / empty = no enforcement (ALLOW).
Semantics:
- Empty
allowed_prompts-> onlyblocked_promptsapplies - Non-empty
allowed_prompts-> ONLY those templates are permitted blocked_promptswins (deny overrides allow)
Context Attributes Read
| Attribute | Phase | Purpose |
|---|---|---|
context.prompt_name | before_workflow | Named template loaded by runtime |
context.metadata["prompt_name"] | before_workflow | Fallback resolver |
Example Policy
Vetted-prompt enterprise mode
{
"name": "Vetted prompts only",
"category": "prompt-allowlist",
"rules": {
"allowed_prompts": [
"research-v3-vetted",
"summarize-v2-legal",
"code-review-v1-approved"
],
"action_on_violation": "block"
},
"scope": {
"agents": ["*"]
},
"enabled": true
}
Block a deprecated prompt
{
"rules": {
"blocked_prompts": ["research-v1-deprecated"],
"action_on_violation": "warn"
}
}
SDK Integration
Set the prompt name via metadata when invoking the agent:
import waxell_observe as waxell
waxell.init()
@waxell.observe(
agent_name="research-assistant",
enforce_policy=True,
metadata={"prompt_name": "research-v3-vetted"},
)
async def research(query: str) -> str:
return await run_with_prompt(query)
Or set context.prompt_name directly if your runtime layer exposes it as an attribute.
Observability
| Field | Example (BLOCK) |
|---|---|
| Category | prompt-allowlist |
| Action | block |
| Reason | Prompt 'ad-hoc-debug' is not on the allowlist |
| Metadata | {"blocked_prompt": "ad-hoc-debug", "allowed_prompts": [...]} |
Common Gotchas
- No
prompt_nameon context = ALLOW. This category is opt-in: runs that don't carry a named template are never blocked. Ensure your runtime populatesprompt_namefor every governed run. - Exact match.
"research"does not match"research-v3-vetted". Use the full canonical name. - Empty allowlist = NO allowlist. Same trap as the other allowlists. Setting
allowed_prompts: []does not block all runs. - Only fires at
before_workflow. The prompt name is locked at run start; mid-run prompt swaps aren't checked. If your runtime supports prompt swapping mid-workflow, you need to re-evaluate at the swap point. - Cross-reference with
Promptrows. The allowlist is just a string match -- it does not validate that the prompt actually exists in the prompt registry. Pair with deployment hygiene to keep the two in sync. - Three handlers, one module. tool-allowlist, mcp-server-allowlist, and
prompt-allowlistshareallowlists.py.
Next Steps
- Tool Allowlist -- Positive list governance for tools
- MCP Server Allowlist -- Positive list governance for MCP servers
- Safety Policy -- Content filters on prompts (PII, credentials)
- Code Execution Policy -- Sandbox controls for code-exec tools
- Policy Categories & Templates -- All categories