Action Types
HushSpec defines a standard taxonomy of action types. Engines use action types to route evaluation to the appropriate rule blocks. Each action type represents a distinct category of agent behavior that may be controlled by one or more security rules.
Action-to-Rule Mapping#
The following table shows every action type and which rule blocks are evaluated when that action occurs.
| Action Type | Description | Evaluated Rule Blocks |
|---|---|---|
file_read | Reading a file from the filesystem | forbidden_paths, path_allowlist |
file_write | Writing or creating a file | forbidden_paths, path_allowlist, secret_patterns |
egress | Outbound network request | egress |
shell_command | Executing a shell command | shell_commands |
tool_call | Invoking a tool or MCP endpoint | tool_access |
patch_apply | Applying a patch or diff to a file | patch_integrity, forbidden_paths, path_allowlist, secret_patterns |
computer_use | Computer use agent action | computer_use |
input_inject | Injecting keyboard, mouse, or touch input | input_injection |
custom | Engine-defined action type | tool_access (if name matches), otherwise engine-specific |
Evaluation Flow#
When an agent runtime intercepts an action, the following evaluation process occurs:
- Action arrives. The engine captures the action type and its context (path, domain, command string, tool name, content, etc.).
- Rule routing. The engine identifies which rule blocks apply to this action type using the mapping above.
- Per-rule evaluation. Each applicable and enabled rule block independently evaluates the action and produces a decision:
allow,warn, ordeny. - Decision aggregation. All decisions are collected and the most restrictive one wins, using the precedence order:
deny>warn>allow. - Final decision. The engine enforces the aggregated decision.
Disabled rule blocks (enabled: false) are skipped entirely and produce no decision. If no enabled rule blocks apply to an action, the action is allowed by default.
Decision Types#
Rules produce one of three standard decision outcomes:
| Decision | Precedence | Meaning |
|---|---|---|
deny | Highest | The action is blocked. Execution MUST NOT proceed. |
warn | Middle | The action is permitted pending confirmation. Engines determine how confirmation is obtained (interactive prompt, approval queue, auto-approve in CI, etc.). If confirmation is not possible, engines SHOULD treat warn as deny. |
allow | Lowest | The action is permitted. Execution may proceed. |
The precedence rule is simple: a single deny from any applicable rule block overrides everything else. This is the fail-closed principle applied to runtime evaluation.
Multi-Rule Evaluation Examples#
Most action types are evaluated against multiple rule blocks simultaneously. The following examples illustrate how this works in practice.
Example 1: file_write to a sensitive path with secrets#
An agent attempts to write a file to src/config.js that contains an AWS access key.
rules:
forbidden_paths:
patterns: ["**/.env", "**/.ssh/**"]
path_allowlist:
enabled: true
write: ["src/**"]
secret_patterns:
patterns:
- name: "aws_key"
pattern: "AKIA[0-9A-Z]{16}"
severity: "critical"Evaluation:
forbidden_paths:src/config.jsdoes not match**/.envor**/.ssh/**→ allowpath_allowlist:src/config.jsmatchessrc/**in write list → allowsecret_patterns: content containsAKIA...at severitycritical→ deny
Aggregated result: deny. The secret detection overrides the path permissions.
Example 2: patch_apply with multiple checks#
An agent applies a 50-line patch to lib/utils.py.
rules:
forbidden_paths:
patterns: ["**/node_modules/**"]
patch_integrity:
max_additions: 200
max_deletions: 100
secret_patterns:
patterns:
- name: "generic_api_key"
pattern: "(?i)api[_-]?key\\s*[=:]\\s*['\"]?[a-z0-9]{32,}"
severity: "error"Evaluation:
forbidden_paths:lib/utils.pydoes not match → allowpatch_integrity: 50 additions is within the 200 limit → allowsecret_patterns: no API key pattern found in patch content → allow
Aggregated result: allow. All three rule blocks permit the action.
Example 3: tool_call with confirmation#
An agent invokes the deploy tool.
rules:
tool_access:
block: ["rm_database"]
require_confirmation: ["deploy", "database_write"]
default: "allow"Evaluation:
tool_access:deployis not inblock, but it is inrequire_confirmation→ warn
Aggregated result: warn. The engine prompts for confirmation before allowing the tool call to proceed. If running in a non-interactive context where confirmation is impossible, the engine should treat this as deny.
Example 4: file_write to a forbidden path#
An agent writes to .env which is clean (no secrets detected).
rules:
forbidden_paths:
patterns: ["**/.env"]
exceptions: ["**/.env.example"]
secret_patterns:
patterns:
- name: "aws_key"
pattern: "AKIA[0-9A-Z]{16}"
severity: "critical"Evaluation:
forbidden_paths:.envmatches**/.envand does not match exceptions → denysecret_patterns: no secrets in content → allow
Aggregated result: deny. The path rule blocks the write regardless of the content being clean.