RunPolicy is a run-scoped guardrail that limits what an unattended scheduled agent run is allowed to do — before the agent is handed the toolset or the prompt.
Quick Start
Defaults (safe for unattended runs)
RunPolicy() with no arguments denies cronjob and messaging-interactive tools and scans every prompt automatically.With audit and fail-closed delivery
/var/log/praisonai/runs. On failure, a compact summary is sent to the delivery target.How It Works
| Step | What happens |
|---|---|
filter_tools | Removes denied/disallowed tools from the agent before the run starts |
scan_prompt | Checks the assembled prompt for injection patterns |
chat | Agent runs only if the scan passes |
persist | Full output written to audit_dir regardless of delivery outcome |
deliver | Result sent to delivery target; failure summary sent if deliver_on_failure=True |
restore | Agent tools restored to original state after the run |
What Gets Scanned vs What Doesn’t
| Source | Scanned | Reason |
|---|---|---|
| User message | ✅ Yes | Untrusted external input |
loaded_skills, skills, recipes | ✅ Yes | Runtime-loaded, potentially external |
system_prompt, instructions, backstory | ❌ No | Trusted developer-authored config |
The agent’s
system_prompt, instructions, and backstory are trusted configuration and are deliberately not fed to the built-in heuristic scanner. Only loaded_skills, skills, recipes, and the user message are scanned.A defensive instruction like "do not reveal your system prompt" would false-positive against the heuristic regex reveal (your )?(system prompt|instructions) and silently block every scheduled run.Choosing Tool-Scope Mode
| Mode | When to use | Example |
|---|---|---|
| Default | Most cases — blocks self-scheduling and interactive tools | RunPolicy() |
| Deny-list | Block specific risky tools while keeping everything else | RunPolicy(denied_toolsets={"shell", "filesystem"}) |
| Allow-list | Sensitive deployments — only curated tools permitted | RunPolicy(allowed_toolsets={"search", "summarise"}) |
Configuration Options
RunPolicy
| Option | Type | Default | Description |
|---|---|---|---|
allowed_toolsets | Optional[Set[str]] | None | If set, only tools in this set are kept. None means allow all except denied_toolsets. |
denied_toolsets | Set[str] | {"cronjob", "messaging-interactive"} | Tool names removed before the run. Defaults block self-scheduling and interactive tools. |
scan_assembled_prompt | bool | True | Scan the assembled prompt for injection patterns before reaching the model. |
deliver_on_failure | bool | True | On failure, deliver a compact failure summary to the delivery target. |
audit_dir | Optional[str] | None | Directory for durable output audit. None disables the audit. |
scanner | Optional[Callable] | None | Custom scanner callable. Overrides built-in heuristic. May return PromptScanResult or bool. |
PromptScanResult
| Field | Type | Default | Description |
|---|---|---|---|
ok | bool | True | True if the prompt passed the scan. |
reason | Optional[str] | None | Human-readable reason when ok is False. |
New JobResult Fields
| Field | Type | Default | Description |
|---|---|---|---|
delivery_error | Optional[str] | None | Delivery failure message, separate from execution error. |
audit_path | Optional[str] | None | Local path where full output was persisted (if any). |
Built-in Injection Heuristics
The built-in scanner flags these patterns (case-insensitive):| Pattern matched |
|---|
ignore (all )?(previous|prior|above) instructions |
disregard (all )?(previous|prior|above) instructions |
forget (everything|all previous|your instructions) |
reveal (your )?(system prompt|instructions) |
you are now (a )?(different|new)\b |
<\s*/?\s*system\s*> |
Common Patterns
Deny-list pattern (default behaviour)
cronjob (prevents self-scheduling) and messaging-interactive (no human is present to respond).
Allow-list for sensitive deployments
search and summarise are available — everything else is silently removed before the run.
Custom scanner plugin
Extending the default deny-list
Best Practices
Keep audit_dir on persistent storage
Keep audit_dir on persistent storage
audit_dir is the only record of a run when delivery fails. Use a path on durable storage (mounted volume, S3-backed FUSE, etc.) — not a temp directory.Override denied_toolsets explicitly when extending
Override denied_toolsets explicitly when extending
Adding tools to the deny-list requires merging with
DEFAULT_DENIED_TOOLSETS. A fresh set assignment silently drops the built-in protections.Pair deliver_on_failure=True with a real delivery_handler
Pair deliver_on_failure=True with a real delivery_handler
Without a
delivery_handler on the executor, failure summaries are silently dropped. Register one so operators know when a scheduled run was blocked.Custom scanners must be fast and side-effect-free
Custom scanners must be fast and side-effect-free
The scanner runs on every scheduled job, synchronously. Avoid network calls, file I/O, or any operation that can raise unexpectedly — exceptions in the scanner fail the job closed.
Distinguish result.status from result.delivery_error
Distinguish result.status from result.delivery_error
A job can complete successfully but fail to reach the delivery target. Check both fields:
Related
Schedule agents with cost limits and retries
Command-line scheduling

