Quick start
This walkthrough covers writing a rule file, validating it, and testing it against fixture data. By the end you will have a working policy that denies two dangerous Linear operations.
Prerequisites
keepCLI installed
1. Write a rule file
Create a rules/ directory and add a rule file:
$ mkdir -p rules
Save the following as rules/linear.yaml:
scope: linear-tools
rules:
- name: no-delete
match:
operation: "delete_issue"
action: deny
message: "Issue deletion is not permitted. Archive instead."
- name: no-auto-p0
match:
operation: "create_issue"
when: "params.priority == 0"
action: deny
message: "P0 issues must be created by a human. Use priority 1 or lower."
The first rule denies any delete_issue call outright. The second uses a CEL expression to deny create_issue only when the priority is 0. All other operations are allowed by default.
2. Validate your rules
$ keep validate ./rules
OK (1 scopes, linear-tools: 0 errors)
keep validate loads every rule file in the directory, compiles CEL expressions, and reports errors. If a file has a syntax error or an invalid expression, the command exits with a non-zero status and prints the problem.
3. Write a fixture file
Fixtures let you test rules against sample calls without running a live service. Create a fixtures/ directory:
$ mkdir -p fixtures
Save the following as fixtures/linear.yaml:
scope: linear-tools
tests:
- name: block delete_issue
call:
operation: delete_issue
expect:
decision: deny
rule: no-delete
message: "Issue deletion is not permitted."
- name: block P0 creation
call:
operation: create_issue
params:
priority: 0
title: "Server on fire"
expect:
decision: deny
rule: no-auto-p0
- name: allow P1 creation
call:
operation: create_issue
params:
priority: 1
title: "Fix login timeout"
expect:
decision: allow
Each test specifies a call (operation and params) and the expected decision. You can also assert the rule name and message.
4. Run the tests
$ keep test ./rules --fixtures ./fixtures
linear.yaml:
PASS block delete_issue
PASS block P0 creation
PASS allow P1 creation
3 tests, 3 passed, 0 failed
All three calls are evaluated against the rules in ./rules. The two deny cases match, and the P1 creation falls through to the default allow.
Tip:
keep testforcesenforcemode regardless of what the rule file declares. This means rules withmode: audit_onlystill fire during testing so you can verify behavior before enabling enforcement.
Next steps
You have rules that validate and pass tests. To enforce them at runtime:
- Run the MCP relay — proxy MCP tool calls through Keep so agents hit your policy before reaching upstream servers
- Run the LLM gateway — sit between your agent and the LLM provider to filter both requests and responses