Portable guardrails for any agent runtime.
Safety rules as data, not code. Define what your agent can and can't do in YAML, and Reflex enforces it -- across Claude Code, MCP servers, Cursor, or any runtime with an adapter.
Agent safety shouldn't be hardcoded into a single platform's hook system. Reflex separates what the rules are from where they run:
- Rules are YAML files. Readable, versionable, shareable.
- Core rules can't be disabled. Tier enforcement prevents agents from weakening their own guardrails.
- One rule set, many runtimes. Write rules once, enforce them everywhere your agent operates.
npm install @fozikio/refleximport { RuleEngine, CORE_RULES, loadRuleDirectory } from '@fozikio/reflex';
// Initialize with core safety rules
const engine = new RuleEngine({ allowed_roots: 'D:/projects, /home/user' });
engine.addRules(CORE_RULES);
// Load custom rules from YAML files
const customRules = await loadRuleDirectory('./rules');
engine.addRules(customRules);
// Evaluate an event
const results = engine.evaluate({
event: 'file_write',
file_path: '/etc/passwd',
content: 'something dangerous',
});
// Check if an action is allowed
if (!engine.isAllowed({ event: 'bash_command', command: 'rm -rf /' })) {
console.log('Blocked by reflex');
}Rules are YAML files with a flat, declarative structure:
name: block-dangerous-rm
version: 1
tier: core
category: safety
description: Block catastrophic shell commands
events: [bash_command]
conditions:
- field: command
op: regex
pattern: 'rm\s+-rf\s+[/~.]'
action: block
severity: critical
message: "Destructive command blocked: {{command}}"
override:
allow_disable: false
allow_downgrade: false| Field | Type | Description |
|---|---|---|
name |
string | Unique rule identifier |
version |
number | Rule version (for evolution tracking) |
tier |
core | recommended | custom |
Enforcement tier |
category |
safety | quality | style | cognitive |
Rule category |
description |
string | Human-readable description |
events |
array | Events that trigger evaluation |
conditions |
array | All must match for rule to trigger |
action |
block | warn | log |
What happens when triggered |
severity |
critical | high | medium | low | info |
Severity level |
message |
string | Message shown when triggered (supports {{var}} templates) |
override |
object | Whether the rule can be disabled or downgraded |
| Event | Triggers on |
|---|---|
bash_command |
Shell command execution |
file_write |
New file creation |
file_edit |
Existing file modification |
file_delete |
File deletion |
prompt_submit |
User prompt submission |
session_start |
Agent session starting |
session_stop |
Agent session ending |
tool_call |
Any tool invocation |
post_tool |
After a tool completes |
any |
All events |
| Operator | Behavior |
|---|---|
matches |
Glob-style matching (comma-separated patterns, * wildcards) |
not_matches |
Inverse of matches |
contains |
Substring check |
not_contains |
Inverse of contains |
equals |
Exact string match |
not_equals |
Inverse of equals |
starts_with |
Prefix check |
ends_with |
Suffix check |
regex |
Full regex match |
Rule messages and condition patterns support {{variable}} templates. Variables are set at engine initialization and can reference event data:
const engine = new RuleEngine({
allowed_roots: 'D:/projects, /home/user',
owner: 'idapixl',
});message: "Write blocked: {{file_path}} is outside {{allowed_roots}}"Rules have three tiers with different enforcement guarantees:
| Tier | Can disable? | Can downgrade? | Use case |
|---|---|---|---|
core |
No | No | Safety invariants (write boundaries, destructive command blocking) |
recommended |
Yes | Yes | Best practices (credential checks, style rules) |
custom |
Yes | Yes | User-defined rules |
Core rules ship with the package and cannot be weakened by configuration:
import { CORE_RULES } from '@fozikio/reflex';
// write-boundary, destructive-commands, path-traversal, credential-protectionconst engine = new RuleEngine(variables?: Record<string, string | string[]>);
engine.addRule(rule: ReflexRule): void;
engine.addRules(rules: ReflexRule[]): void;
engine.setVariable(key: string, value: string | string[]): void;
// Returns all triggered rules
engine.evaluate(event: ReflexEventData): EvaluationResult[];
// Returns only blocking results
engine.getBlocks(event: ReflexEventData): EvaluationResult[];
// Returns true if no blocking rules trigger
engine.isAllowed(event: ReflexEventData): boolean;// Load a single YAML rule
const rule = await loadRuleFile('./rules/my-rule.yaml');
// Load all .yaml/.yml files from a directory (recursive)
const rules = await loadRuleDirectory('./rules', config?);The optional ReflexConfig lets you disable specific rules by name (respecting tier enforcement):
const config: ReflexConfig = {
allowed_roots: ['D:/projects'],
disabled_rules: ['warn-debug-code'], // only works for recommended/custom tier
rule_dirs: ['./rules', './extra-rules'],
};See the Contributing Guide. Report security issues via SECURITY.md.
- cortex-engine — Cognitive memory layer for AI agents (ships with Reflex rules)
- sigil — Agent control surface
- fozikio.com — Documentation and guides
- r/fozikio — Community
Reflex is the successor to Hookify, a Claude Code plugin that used markdown files with YAML frontmatter for hook rules. Reflex takes the same idea -- rules as data -- and makes it portable, typed, and enforceable across any agent runtime.
Part of the Fozikio agent toolkit.
MIT