Rule Syntax Reference
SigmaShake rules use a declarative DSL designed for readability and safety. Each rule defines a condition that matches tool calls and a decision to apply.
Basic structure
rule <rule_id> {
enabled true
priority <number>
severity <error|warning|info>
<DECISION> <target>
IF <condition>
MESSAGE "<text>"
[CONTEXT "<text>"]
[RUN "<command>"]
[WEBHOOK "<url>"]
}
Minimal example
rule no-rm-rf {
enabled true
DENY execution
IF command CONTAINS "rm -rf"
MESSAGE "Destructive command blocked."
}
Default values when omitted:
priority→50severity→warningenabled→true
Rule ID
Must be a valid identifier: letters, numbers, hyphens, underscores. Used in audit logs and API responses.
rule my-rule-123 { ... }
rule ts_write_safety { ... }
Decision types
| DSL Keyword | Runtime Decision | Behavior |
|---|---|---|
DENY | block | Reject the tool call |
ALLOW | allow | Permit explicitly (overrides lower-priority DENY) |
LOG | log | Allow but record in audit log |
SHADOW | shadow | Allow silently, log for monitoring |
ASK | ask | Pause execution, require human approval via dashboard |
FORCE | force | Block and return an error prompting the agent to use a safer substitute command |
Not every rule has a decision. Ambient knowledge rules carry standing project context and never gate a tool call, so they omit the decision keyword entirely —
AMBIENTis a rule directive, not a seventh decision type. See Ambient knowledge rules below.
ASK decisions
Require a PROMPT field:
rule ask-before-reset {
enabled true
ASK execution
IF command CONTAINS "git reset --hard"
MESSAGE "Hard reset requires approval."
PROMPT "Allow git reset --hard?"
}
FORCE decisions
Require a SUBSTITUTE field:
rule force-exact-pins {
enabled true
FORCE execution
IF command REGEX "npm install\\s+\\S+@\\^"
MESSAGE "Use exact version pins."
SUBSTITUTE "npm install package@1.2.3"
}
CONTEXT — surface text to the AI
CONTEXT "<text>" is an optional directive that injects text into the AI's view when the rule matches. It is orthogonal to the decision — combinable with ALLOW, LOG, SHADOW, BLOCK (DENY), ASK, and FORCE.
Use it to drop a reminder, hint, or runbook link without blocking the tool call:
rule remind-elixir-tests {
enabled true
ALLOW execution
IF command CONTAINS "mix test"
MESSAGE "Heads up."
CONTEXT "OTP 28 hangs mix test on this box. Use `mix help test.<alias>` instead."
}
When the rule fires, Claude Code receives the text and prepends it to the tool result the model sees on the next turn — so the AI can adjust without the user having to intervene.
How it reaches the AI by decision
| Decision | Wire format |
|---|---|
ALLOW, LOG, SHADOW | Emitted as Claude Code hookSpecificOutput.additionalContext (PreToolUse). Tool runs; AI sees the context with the result. |
DENY (block) / FORCE | Appended to the stderr block message. Claude Code surfaces stderr to the model on exit-code 2. |
ASK | Emitted alongside permissionDecisionReason as additionalContext in the same hookSpecificOutput JSON — the user sees the reason in the approval dialog, the AI sees the context once the call resumes. |
When to use CONTEXT vs. MESSAGE
MESSAGEis for humans — shown in dashboards, audit logs, and the approval prompt.CONTEXTis for the AI — fed back into the model's reasoning loop so it changes its next action.
They are complementary; most rules will set both.
Constraints
- Empty strings are rejected at parse time (
CONTEXT ""→ parse error). - One
CONTEXTper rule; last write wins if duplicated. - Survives
auditandsoftruntime modes (it never enforces, so it never needs to be downgraded).
Ambient knowledge rules
An ambient rule carries always-on project knowledge instead of gating a tool call. It has no decision and no IF/OR conditions — it is never evaluated against tool calls. Instead, its MESSAGE + CONTEXT are surfaced to the agent at session start by ssg hook session-start. This is the SSG-native equivalent of an AI-agent memory file.
Mark a rule ambient with the standalone AMBIENT directive:
rule mem_otp28_mix_test_hang {
priority 80
severity warning
AMBIENT
MESSAGE "OTP 28 silently hangs `mix test` on this box."
CONTEXT "The erl_child_setup bug hangs the test wrapper on 64+ core machines. Verify changes with `mix compile` or `mix help test.<alias>` instead — the main agent runs `mix test` synchronously when asked."
}
Fields
| Field | Required | Purpose |
|---|---|---|
AMBIENT | yes | Marks the rule as a knowledge carrier. Takes no decision keyword. |
MESSAGE | yes | One-line headline. Shown in the session-start index. |
CONTEXT | yes | The knowledge body. Pulled on demand via ssg recall. |
priority | no | Higher = listed first at session start. Default 50. |
severity | no | Informational label only (error/warning/info). Default warning. |
An ambient rule takes no <DECISION>, no target, and no IF/AND/OR conditions — only the metadata above.
Session start and recall
At session start, ssg hook session-start emits a compact index of every ambient rule — one MESSAGE headline per entry, grouped by area — rather than dumping every CONTEXT body, keeping the injected context small.
Pull the full CONTEXT for any entry on demand:
ssg recall <keyword-or-id> # full MESSAGE + CONTEXT for matching entries
ssg recall # reprint the headline index
Ambient rule vs. CONTEXT on a gating rule
Both surface text to the AI, but at different times and for different reasons:
| Ambient rule | CONTEXT on a gating rule | |
|---|---|---|
| When | Session start, always | When the rule matches a tool call |
| Trigger | None — unconditional | The rule's IF conditions |
| Decision | None | ALLOW / LOG / DENY / ASK / FORCE / SHADOW |
| Use for | Standing project knowledge | A just-in-time hint tied to a specific action |
Where ambient rules live
By convention, ambient knowledge lives in mem_*.rules files under .sigmashake/rules/. The ambient flag is a file-level field — like RUN and WEBHOOK, it is not persisted to the rules database, and loadRulesFromFiles excludes ambient rules from the evaluator's active set so they never participate in tool-call decisions.
In the dashboard, ambient rules appear on the Rules page with a teal AMBIENT badge in place of the decision selector — a visual reminder that they carry no verdict.
Triggers (optional)
Any rule can include RUN and/or WEBHOOK lines that fire asynchronously when the rule matches. Triggers are fire-and-forget — failures log to stderr but never block eval output.
RUN — execute a script
rule block-and-notify {
enabled true
DENY execution
IF command CONTAINS "rm -rf"
MESSAGE "Destructive command blocked."
RUN "./scripts/on-block.sh"
}
The script receives a JSON payload on stdin:
{
"tool": "Bash",
"input": {"command": "rm -rf /"},
"rule_id": "block-and-notify",
"decision": "block",
"matched_pattern": "command CONTAINS \"rm -rf\""
}
WEBHOOK — send an HTTP POST
rule audit-network {
enabled true
LOG network
IF tool EQUALS "WebFetch"
MESSAGE "Network request logged."
WEBHOOK "https://hooks.slack.com/services/T00/B00/xxx"
}
The webhook receives the same JSON payload as the POST body (Content-Type: application/json). Timeout is 5 seconds.
Combining triggers with any decision
Triggers work with all decision types — DENY, ALLOW, LOG, SHADOW, ASK, FORCE. You can use both RUN and WEBHOOK on the same rule:
rule full-trigger {
enabled true
DENY execution
IF command CONTAINS "drop table"
MESSAGE "SQL drop blocked."
RUN "./scripts/alert.sh"
WEBHOOK "https://example.com/audit"
}
Targets
Targets determine which tool capability a rule applies to:
| Target | Matches tools with capability |
|---|---|
execution | Shell commands (Bash, terminal) |
read | File reading (Read, cat) |
write | File writing/editing (Write, Edit) |
edit | Edit only (subset of write) |
search | File/content search (Glob, Grep) |
agent | Sub-agent spawning (Agent) |
network | HTTP requests (WebFetch, WebSearch) |
any | All tools |
Conditions
Syntax
IF <field> [NOT] <operator> "<value>"
Fields
| Field | Resolves to |
|---|---|
command | input.command (Bash commands) |
path | input.file_path or input.path |
content | input.content or input.new_string |
tool | Tool name (e.g., "Bash", "Read") |
input.<key> | Any key in the tool input object |
Operators
| Operator | Description |
|---|---|
CONTAINS | Substring match |
EQUALS | Exact string match |
STARTS_WITH | Prefix match |
ENDS_WITH | Suffix match |
GLOB | Glob pattern (*, **, ?) |
REGEX | Regular expression |
WORD | Word-boundary match (no regex, O(n)) |
LINE_CONTAINS | Per-line substring, strips // comments |
LINE_REGEX | Per-line regex, strips // comments |
All operators support NOT for negation:
IF command NOT CONTAINS "echo"
AND / OR logic
Within a block, conditions are AND-ed. Use OR to start a new group:
rule block-secret-writes {
enabled true
DENY write
IF path ENDS_WITH ".env"
AND content CONTAINS "API_KEY"
OR path ENDS_WITH ".env.local"
AND content CONTAINS "SECRET"
MESSAGE "Cannot write secrets to env files."
}
This means: (path ends with .env AND content contains API_KEY) OR (path ends with .env.local AND content contains SECRET).
Priority
Higher priority rules are evaluated first. First match wins (short-circuit).
rule allow-echo {
enabled true
priority 100
ALLOW execution
IF command STARTS_WITH "echo"
MESSAGE "Echo commands are always allowed."
}
rule block-all-bash {
enabled true
priority 50
DENY execution
IF tool EQUALS "Bash"
MESSAGE "Bash commands require approval."
}
With priority 100 > 50, echo hello matches allow-echo first and is allowed.
Generic input fields
Access any key in the tool input object using input.<key>:
rule log-explore-agents {
enabled true
LOG agent
IF input.subagent_type EQUALS "Explore"
MESSAGE "Explore agent activity logged."
}
rule block-background-agents {
enabled true
DENY agent
IF input.run_in_background EQUALS "true"
AND input.subagent_type NOT EQUALS "general-purpose"
MESSAGE "Only general-purpose agents may run in background."
}
Non-string values are JSON-stringified before matching. Missing fields resolve to empty string (no match for positive conditions).
Enabling/disabling
rule temporarily-disabled {
enabled false
DENY execution
IF command CONTAINS "test"
MESSAGE "This rule is off."
}
File naming convention
Follow the Sigma-style convention: {technology}_{capability}_{description}.rules
Examples:
ts_write_safety.rulesgit_exec_trunk_workflow.rulesbash_exec_destructive_ops.rulesagent_exec_oracle_redirect.rules