Portable, open specification for AI agent security rules
Spec · Docs · Rulesets · JSON Schema
HushSpec is an open policy format for AI agent security rules. It defines what an agent may do at runtime, including filesystem access, network egress, tool usage, secret detection, and more, without prescribing how those controls must be enforced. That separation makes policies portable across runtimes, frameworks, and languages.
v0.1.1-alpha — The core spec, all four SDKs (Rust, TypeScript, Python, Go), and the h2h CLI are published and functional. Parse, validate, evaluate, merge, resolve, detect, sign, and audit your way through 10 rule types and 3 extension modules. The API surface is stabilizing but not yet frozen — expect refinements before v1.0.
hushspec: "0.1.0"
name: production-agent
rules:
forbidden_paths:
patterns:
- "**/.ssh/**"
- "**/.aws/**"
- "/etc/shadow"
egress:
allow:
- "api.openai.com"
- "*.anthropic.com"
- "api.github.com"
default: block
tool_access:
block: [shell_exec, run_command]
require_confirmation: [file_write, git_push]
default: allow
secret_patterns:
patterns:
- name: aws_key
pattern: "AKIA[0-9A-Z]{16}"
severity: critical
skip_paths: ["**/test/**"]
shell_commands:
forbidden_patterns:
- "rm\\s+-rf\\s+/"
- "curl.*\\|.*bash"All four SDKs implement the full HushSpec pipeline, from parse and validate through resolution and evaluation.
| Capability | Rust | TypeScript | Python | Go |
|---|---|---|---|---|
| Parse + Validate (Level 1) | Yes | Yes | Yes | Yes |
| Merge (Level 2) | Yes | Yes | Yes | Yes |
| Resolve (Level 2+) | Yes | Yes | Yes | Yes |
| Evaluate (Level 3) | Yes | Yes | Yes | Yes |
| Audit Trail (Level 4) | Yes | Yes | Yes | Yes |
| Detection | Yes | Yes | Yes | Yes |
| Observability | Yes | Yes | Yes | Yes |
| Receipt Sinks | Yes | Yes | Yes | Yes |
cargo install hushspec-cliThis installs the h2h command. See CLI Tool below.
[dependencies]
hushspec = "0.1"npm install @hushspec/corepip install hushspecgo get github.com/backbay-labs/hush/packages/go@mainuse hushspec::HushSpec;
let yaml_str = "hushspec: \"0.1.0\"\nname: example\n";
let spec = HushSpec::parse(yaml_str)?;
let result = hushspec::validate(&spec);
assert!(result.is_valid());import { parseOrThrow, validate } from '@hushspec/core';
const yamlString = 'hushspec: "0.1.0"\nname: example\n';
const spec = parseOrThrow(yamlString);
const result = validate(spec);
console.log(result.valid); // truefrom hushspec import parse_or_raise, validate
yaml_string = 'hushspec: "0.1.0"\nname: example\n'
spec = parse_or_raise(yaml_string)
result = validate(spec)
assert result.is_validimport (
"fmt"
"github.com/backbay-labs/hush/packages/go/hushspec"
)
yamlString := "hushspec: \"0.1.0\"\nname: example\n"
spec, err := hushspec.Parse(yamlString)
if err != nil {
panic(err)
}
result := hushspec.Validate(spec)
fmt.Println(result.IsValid())Each SDK exposes an evaluate() function that takes a parsed spec and an action, then returns a decision (allow, warn, or deny) plus matched rule details.
import { parseOrThrow, evaluate } from '@hushspec/core';
const spec = parseOrThrow(policyYaml);
const result = evaluate(spec, { type: 'egress', target: 'api.openai.com' });
// result.decision === 'allow' | 'warn' | 'deny'
// result.matched_rule === 'egress'from hushspec import parse_or_raise, evaluate
spec = parse_or_raise(policy_yaml)
result = evaluate(spec, {"type": "egress", "target": "api.openai.com"})
assert result.decision in ("allow", "warn", "deny")HushGuard wraps policy loading and evaluation behind a simple evaluate, check, and enforce interface for application code.
import { HushGuard } from '@hushspec/core';
const guard = HushGuard.fromFile('./policy.yaml');
guard.enforce({ type: 'tool_call', target: 'bash' }); // throws HushSpecDenied if deniedfrom hushspec import HushGuard
guard = HushGuard.from_file("./policy.yaml")
guard.enforce({"type": "tool_call", "target": "bash"}) # raises HushSpecDenied if deniedThe h2h CLI covers the common policy workflow: validate, test, lint, diff, format, initialize, sign, verify, and trigger panic mode.
# Validate a policy against the HushSpec schema
h2h validate policy.yaml
# Run evaluation test suites
h2h test --fixtures ./tests/
# Static analysis and linting
h2h lint policy.yaml
# Compare two policies and show effective decision changes
h2h diff old.yaml new.yaml
# Format policy files canonically
h2h fmt policy.yaml
# Scaffold a new policy project
h2h init --preset default
# Sign a policy with Ed25519
h2h sign policy.yaml --key h2h.key
# Verify a policy signature
h2h verify policy.yaml --key h2h.pub
# Generate a new Ed25519 keypair
h2h keygen
# Emergency override (deny-all kill switch)
h2h panic activate --sentinel /tmp/hushspec.panic
h2h panic deactivate --sentinel /tmp/hushspec.panicInstall from crates.io:
cargo install hushspec-cliDecision Receipts (Audit Trail)
evaluate_audited() generates structured decision receipts with rule traces, policy summaries, and optional content redaction. Receipts conform to hushspec-receipt.v0.schema.json and are designed to support audit-heavy environments such as SOC 2, HIPAA, PCI-DSS, and FedRAMP.
import { parseOrThrow, evaluateAudited } from '@hushspec/core';
const spec = parseOrThrow(policyYaml);
const receipt = evaluateAudited(spec, action, {
enabled: true,
include_rule_trace: true,
redact_content: false,
});
// receipt.decision, receipt.rule_evaluations, receipt.policy_summaryReceipt sinks (FileReceiptSink, ConsoleReceiptSink, FilteredSink, MultiSink, CallbackSink) are available in all four SDKs for routing receipts to storage, logging, or OTLP endpoints.
Detection Pipeline
The detection pipeline plugs prompt injection, jailbreak, and exfiltration checks into the evaluation flow. Regex-based reference detectors ship with all SDKs, and custom detectors can be registered through DetectorRegistry.
import { parseOrThrow, evaluateWithDetection, DetectorRegistry } from '@hushspec/core';
const registry = DetectorRegistry.withDefaults();
const result = evaluateWithDetection(spec, action, registry, {
enabled: true,
prompt_injection_threshold: 0.5,
});
// result.detection_results contains matched patterns and confidence scoresFramework Adapters
Prebuilt adapters translate framework-specific tool calls into HushSpec evaluation actions.
| Framework | Adapter | SDK |
|---|---|---|
| Claude / Anthropic | mapClaudeToolToAction, createSecureToolHandler |
TypeScript |
| OpenAI | mapOpenAIToolCall, createOpenAIGuard |
TypeScript |
| MCP (Model Context Protocol) | mapMCPToolCall, createMCPGuard |
TypeScript |
import { HushGuard, mapClaudeToolToAction } from '@hushspec/core';
const guard = HushGuard.fromFile('./policy.yaml');
const action = mapClaudeToolToAction(toolUseBlock);
guard.enforce(action);Observability
The EvaluationObserver interface and ObservableEvaluator wrapper emit structured events for every evaluation, policy load, and policy reload. Built-in observers include JsonLineObserver, ConsoleObserver, and MetricsCollector.
import { ObservableEvaluator, JsonLineObserver, MetricsCollector } from '@hushspec/core';
const evaluator = new ObservableEvaluator();
evaluator.addObserver(new JsonLineObserver(process.stderr));
evaluator.addObserver(new MetricsCollector());
const result = evaluator.evaluate(spec, action);Policy Signing
Policies can be signed with Ed25519 keys and verified at load time. The CLI provides sign, verify, and keygen commands. The signature format conforms to hushspec-signature.v0.schema.json.
# Generate a keypair
h2h keygen --output-dir mykeys
# Sign a policy (creates policy.yaml.sig)
h2h sign policy.yaml --key mykeys/h2h.key
# Verify the signature
h2h verify policy.yaml --key mykeys/h2h.pubEmergency Override (Panic Mode)
Panic mode is a deny-all kill switch that can be activated immediately without redeploying policies. You can trigger it with a sentinel file, the CLI, or an API call. While panic mode is active, every evaluation returns deny.
# Activate panic mode
h2h panic activate --sentinel /tmp/hushspec.panic
# Deactivate
h2h panic deactivate --sentinel /tmp/hushspec.panicimport { activatePanic, deactivatePanic, isPanicActive } from '@hushspec/core';
activatePanic();
// All evaluate() calls now return deny
deactivatePanic();Policy Loading and Hot Reload
Policies can be loaded from local files, HTTPS URLs (with ETag caching and SSRF protection), or built-in rulesets. PolicyWatcher and PolicyPoller support hot reload without restarting the process.
import { PolicyWatcher, HushGuard } from '@hushspec/core';
const guard = HushGuard.fromFile('./policy.yaml');
const watcher = new PolicyWatcher('./policy.yaml', {
onChange: (newSpec) => guard.swapPolicy(newSpec),
});
watcher.start();| Rule | Purpose |
|---|---|
forbidden_paths |
Block access to sensitive filesystem paths |
path_allowlist |
Allowlist-based read/write/patch access |
egress |
Network egress control by domain |
secret_patterns |
Detect secrets in file content |
patch_integrity |
Validate diff safety (size limits, forbidden patterns) |
shell_commands |
Block dangerous shell commands |
tool_access |
Control tool/MCP invocations |
computer_use |
Control CUA actions |
remote_desktop_channels |
Control remote desktop side channels |
input_injection |
Control input injection capabilities |
HushSpec supports optional extension modules for more advanced policy behavior:
| Extension | Purpose |
|---|---|
| Posture | Declarative state machine for capabilities and budgets |
| Origins | Origin-aware policy projection (Slack, GitHub, email, etc.) |
| Detection | Threshold config for prompt injection, jailbreak, threat intel |
extensions:
posture:
initial: standard
states:
standard: { capabilities: [file_access, egress] }
restricted: { capabilities: [file_access] }
transitions:
- { from: "*", to: restricted, on: critical_violation }
detection:
prompt_injection:
block_at_or_above: highReady-to-use policies live in rulesets/:
| Ruleset | Description |
|---|---|
default |
Balanced security for AI agent execution |
strict |
Maximum security, minimal permissions |
permissive |
Development-friendly, relaxed limits |
ai-agent |
Optimized for AI coding assistants |
cicd |
CI/CD pipeline security |
remote-desktop |
Computer use agent sessions |
panic |
Deny-all emergency override |
HushSpec documents load natively in Clawdstrike:
// Auto-detects HushSpec vs Clawdstrike-native format
let policy = clawdstrike::Policy::from_yaml_auto(yaml)?;# Convert between formats
hush policy migrate policy.yaml --to hushspecspec/ Normative specification, including core and extension docs
schemas/ JSON Schema definitions
crates/ Rust crates
hushspec/ Core library: parse, validate, merge, resolve, evaluate, detect, sign
hushspec-cli/ CLI tool
hushspec-testkit/ Conformance test runner
packages/ Language SDKs for TypeScript, Python, and Go
rulesets/ Built-in security rulesets
fixtures/ Conformance and evaluation fixtures
docs/ mdBook documentation site
generated/ Generated shared SDK contract artifacts
scripts/ Code generation and CI tooling
- Fail-closed: Unknown fields are rejected, and invalid documents fail with explicit errors.
- Stateless: Core rules are pure declarations with no runtime state.
- Engine-neutral: The spec does not require a specific enforcement engine, detector, or plugin model.
- Extensible: Posture, origins, and detection stay optional instead of bloating the core format.
The normative spec lives in spec/. JSON Schema definitions for programmatic validation are in schemas/. Full documentation is in docs/.
Apache-2.0. See LICENSE.
