Builtin Policies
Omnigent ships with policies for common guardrails, organized into two categories:
Safety and Cost Control. Your Omnigent can apply any of
these by name when you ask it to add a policy, or you
can reference them in YAML by their full path in the handler field.
All builtin policies live under omnigent.policies.builtins.
Safety
| Policy | What it does | Parameters |
|---|---|---|
ask_on_os_tools | ASKs before any file or shell operation. | None |
block_skills | Prevents specific skills from loading. | blocked (string[], required) |
block_working_dir_changes | Blocks shell commands that change the working directory. | block_cd (bool), block_worktree (bool), allowed_dirs (string[]), action ("deny" or "ask") |
cel_policy | Write custom policy logic using CEL (Common Expression Language), a safe, non-Turing-complete expression language. | expression (CEL expression string), reason (deny message) |
deny_pii_in_llm_request | Scans outgoing messages for PII and blocks or flags them. | pii_types (string[]), action ("DENY" or "ASK") |
enforce_sandbox | Forces a sandbox configuration on agent start. | sandbox_type, allow_network, write_paths, read_paths |
gcalendar_policy | Controls Google Calendar. Defaults to read-only. | None |
gdrive_policy | Controls Google Drive, Docs, Sheets, and Slides access. Writes restricted to agent-created files by default. Optionally enforces Bell-LaPadula "no write-down": once the session reads a confidential file, its writes are confined to that set. | read_all, allow_create, write_files, read_files, comment_files, confidential_files (string[]), write_down_action ("DENY" or "ASK", default "DENY") |
github_policy | Controls GitHub read/write access across MCP tools and shell commands. | read_all, write_repos, write_branches |
gmail_policy | Controls Gmail. Defaults to read + draft, no send. | allow_read, allow_send, allow_drafts |
intent_based_authorization | Records the first user message as the session's intent, then ASKs before any tool call that has no plausible connection to that intent. Requires an llm: config block; fails open when none is available. | None |
max_tool_calls_per_session | DENYs after a total tool-call limit is reached. | limit (int, default 100) |
prompt_policy | Evaluate policy decisions using an LLM. The policy sends the event context to a model and interprets the response as ALLOW/ASK/DENY. Useful for nuanced decisions that can't be expressed as static rules. | prompt (system instructions for the evaluator model) |
risk_score_policy | Accumulate a risk score from tool calls and sensitive data labels. Escalates guarded tools to ASK or DENY once the score exceeds a threshold. | threshold (int), tool_points (object mapping tool names to points), sensitive_labels (object mapping labels to points), guarded_tools (string[]), escalate_action ("ASK" or "DENY") |
Orchestration
Safety guardrails for supervisor agents that dispatch sub-agents (like
Polly) — they keep fan-out bounded, writes
contained, and dangerous shell commands in check. They live under
omnigent.policies.builtins.orchestration.
| Policy | What it does | Parameters |
|---|---|---|
blast_radius | Classifies shell commands (sys_os_shell, native Bash, Pi native bash) as safe, risky (ASK), or catastrophic (DENY), e.g. rm -rf / or force-push. | gate_pushes (bool, default true), deny_reason |
spawn_bounds | Limits the number of sub-agent dispatches per turn to prevent runaway fan-out. | max_dispatches_per_turn (int, default 5), dispatch_tools |
headless_subagent_purpose_guard | Requires every sub-agent dispatch to declare a purpose (implement, review, explore, search). | allowed_purposes (string[]), deny_reason |
worktree_guard | Blocks file writes outside the worker's git worktree to prevent cross-branch contamination. | allowed_root (string, default .worktrees), deny_reason |
read_only_os | Denies every file-mutating tool so a report-only agent can read and run shell but never change code. | deny_reason |
Confine confidential Google Drive data (gdrive_policy)
gdrive_policy can layer Bell-LaPadula's classic "no write-down" rule on top
of its access controls. You declare a set of confidential documents up front
with confidential_files (file IDs or Google URLs). The rule engages only once
the session reads one of those files: from then on, its writes are confined
to the confidential set. A write to — or creation of — any other file would move
confidential data into a less-protected place, so it is blocked.
# Omnigent config (policies block)
policies:
confidential_containment:
type: function
handler: omnigent.policies.builtins.google.gdrive_policy
factory_params:
# The confidential compartment: file IDs or Google URLs.
confidential_files:
- "1ConfidentialStrategyDocID"
# Allow creating new files, so a create can be shown being gated as a
# write-down rather than blocked outright by the base access rules.
allow_create: true
# DENY (hard block) or ASK (require human approval) on a write-down.
write_down_action: DENY
Key behaviors:
- Off by default. With no
confidential_files, the base access policy is unchanged. - Read-triggered. Containment engages only after the session reads a confidential file by id. The rule does not restrict reads.
- Not a write grant. Listing a file in
confidential_filesdoes not make it writable — writing to a confidential file still requires it to be created this session or listed inwrite_files. write_down_action."DENY"(default) hard-blocks a write-down;"ASK"routes it to human approval. It is ignored whenconfidential_filesis empty.
Because the confidential set is declared explicitly rather than inferred from a per-document classification label, the rule works on any Google Drive tenant.
Cost Control
| Policy | What it does | Parameters |
|---|---|---|
cost_budget | Tracks cumulative LLM spend per session. ASKs at soft thresholds, blocks expensive models at the hard limit. | max_cost_usd (required), ask_thresholds_usd, expensive_models |
detect_task_switch | Uses the server-level LLM to detect when a user starts a new unrelated task and nudges starting a fresh session. | min_turns (int), history_window (int), action ("ASK" or "DENY", default "ASK"), classification_prompt (string) |
deny_trivial_to_expensive_model | Classifies messages as trivial or complex. Routes trivial tasks away from expensive models. | expensive_models (string[], required), classification_prompt (string) |
subagent_cost_budget | Gates a sub-agent on its own subtree LLM spend. Blocks expensive models at the hard limit, ASKs at soft thresholds. Attach to a child via sys_session_send's cost_budget argument. | max_cost_usd, ask_thresholds_usd, expensive_models |
user_daily_cost_budget | Same as cost_budget, but enforced per-user daily across all sessions. | max_cost_usd (required), ask_thresholds_usd, expensive_models |
Usage examples
Common scenarios: warn an engineer before a session gets expensive, cap daily spend per user across all sessions, or block expensive models once a session hits a hard limit while still letting work continue on a cheaper one.
Make spend visible before you restrict it
Start with soft thresholds only. Engineers see when they're running an expensive session and can decide whether the task warrants it. No one gets blocked; habits change on their own.
# Omnigent config (policies block)
policies:
session_visibility:
type: function
handler: omnigent.policies.builtins.cost.cost_budget
factory_params:
ask_thresholds_usd: [1.0, 5.0]
max_cost_usd: 999.0 # effectively no hard cap
daily_visibility:
type: function
handler: omnigent.policies.builtins.cost.user_daily_cost_budget
factory_params:
ask_thresholds_usd: [10.0, 25.0]
max_cost_usd: 999.0
This gives you real data on where spend is concentrated before you decide where to add guardrails.
Server-wide team policy
A reasonable starting point for a team deployment: per-user daily visibility at $25, a soft check at $50. Engineers can still use any model for any task — they just get asked before spending more than $25 in a day.
# config.yaml
policies:
daily_budget:
type: function
function:
path: omnigent.policies.builtins.cost.user_daily_cost_budget
arguments:
ask_thresholds_usd: [25.0, 50.0]
max_cost_usd: 100.0
omnigent server -c config.yaml
The daily cap exists to surface sessions that are genuinely off the rails, not to penalize productive use.
detect_task_switch
Use this policy to keep sessions focused and avoid wasting tokens on stale context.
On each user request, it classifies whether the latest message continues the
current task or starts a new one, and returns the configured action when it
detects a task switch. It requires a server llm: config and fails open if no
LLM client is available.
# Omnigent config (policies block)
policies:
keep_context_lean:
type: function
handler: omnigent.policies.builtins.context.detect_task_switch
factory_params:
min_turns: 2
history_window: 4
action: ASK