Policy YAML
version: 1
project: acme-checkout
policies:
- name: production-database-protection
match:
actions: ["database.delete", "database.drop"]
environments: ["production"]
decision:
effect: block
reason: No AI-initiated destructive database operations in production.Top level
versionnumber
projectstring
policieslist
Two repositories that declare the same project share one policy and memory
scope. See Orgs, workspaces, projects.
A policy
namestring
descriptionstring
matchobject
decisionobject
match
Every field takes wildcard patterns (*), and an omitted field matches
everything. That default is the most common source of a rule that fires more
widely than intended.
Field
actionstargetsenvironmentsbranchesworkingDirectoriesagentsargumentswindowsarguments
match:
actions: ["shell.execute"]
arguments:
command: ["*rm -rf*"]Every named argument must match. An argument the call does not carry matches only
the bare "*".
Evaluated in-process by @memnox/local-gate, inside the MCP firewall or the
editor hook, so raw payloads never leave the machine.
windows
windows:
- { days: [1,2,3,4,5], startHour: 17, endHour: 9 }
- { days: [0,6], startHour: 0, endHour: 24 }days runs 0 to 6, where 0 is Sunday. Hours are on a 24-hour clock, and a
startHour greater than endHour wraps past midnight, so 17 to 9 means
"overnight". Several windows are OR-ed: the rule applies if the moment falls in
any of them.
The instant is passed into evaluation rather than read from a clock inside the engine, so replay reproduces the same verdict.
decision
effectenum
reasonstring
approverslist
minApprovalsnumber
modeenum
rateLimitobject
Precedence
When several policies match, the most restrictive effect wins:
block > require_approval > redact > allowOrder in the file does not matter. There is no "first match wins", because a rule set whose meaning depends on line order is one that breaks when somebody sorts it.
effect: redact
Masks secrets in the arguments and forwards the call. Needs an enforcement point that can rewrite the payload, the MCP firewall can; an editor hook blocks instead. Masked text is re-scanned, and a surviving finding blocks.
mode: monitor
decision:
effect: block
mode: monitorThe action proceeds and the audit event records the verdict it withheld. This is how one rule is rolled out while the rest of the file enforces.
rateLimit
decision:
effect: allow
rateLimit: { max: 10, windowSeconds: 3600 }Counted per agent and per rule by the runtime. Only an action that actually proceeds spends a slot, and the local gate never counts, this needs a running runtime.
Quorum
decision:
effect: require_approval
approvers: ["eng-lead", "security"]
minApprovals: 2Grants accumulate until the quorum is met. One person counts once, and a single denial ends it.
Validating and simulating
memnox validate [file]
memnox policy simulate -f candidate.yaml
memnox policy versionsimulate replays your real recorded history and warns loudly wherever an action
becomes more permissive.
A fuller example
version: 1
project: acme-checkout
policies:
- name: no-recursive-delete-in-payments
match:
actions: ["shell.execute", "mcp.run_shell"]
arguments: { command: ["*rm -rf*"] }
workingDirectories: ["/srv/payments*"]
decision:
effect: block
reason: Recursive delete is not an agent action here, ask #platform.
- name: release-branches-need-a-human
match:
actions: ["shell.execute"]
arguments: { command: ["*git push*--force*"] }
branches: ["main", "release/*"]
decision:
effect: require_approval
approvers: ["eng-lead"]
reason: A force-push can destroy work that exists nowhere else.
- name: deploy-budget
match:
actions: ["deploy.*"]
environments: ["production"]
decision:
effect: allow
rateLimit: { max: 10, windowSeconds: 3600 }
