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.