Karu is an embeddable policy engine focusing on structural pattern matching over arbitrary JSON data. It is the spiritual successor to the ideas found in logic-based policy languages, designed to solve complex hierarchical data validation that strict-schema engines cannot handle.
It came to be because a coming soon wellknown.id project needed an expressive policy engine as fast as Cedar. That internal project started with Cedar until we accidentally wrote an engine that ran much faster at Cedar than Cedar!. And so it stuck.
| Benchmark | Karu | Cedar | |
|---|---|---|---|
| WASM bundle size | 319 KB | 1.8 MB | 5.6× smaller |
| Native eval (1 rule) | 15 ns | 1,108 ns | 72× faster |
| WASM eval (precompiled) | 465 ns | 88,350 ns | 190× faster |
| Complex (20 rules, native) | 663 ns | 14,137 ns | 21× faster |
| Realistic authz (16 threads) | 14.3M ops/sec | 273K ops/sec | 52× faster |
Karu running in WASM (465 ns) is faster than Cedar running natively (1,108 ns). Full benchmarks →
- Structure over Schema: We do not enforce a schema on input data. We enforce patterns on the data we find.
- Search, Don't Index: If you provide a list, we will search it. You shouldn't have to re-map your application data to fit the policy engine.
- Partial Matching: A pattern
{a: 1}matches{a: 1, b: 2}. - Optionally Strict: When you need Cedar-level rigor, flip a switch. Karu can enforce strict schemas, exhaustive matching, and static analysis - but only when you ask for it. RFCs shouldn't block good ideas.
Rules are allow or deny, with an optional if body:
allow public_access;
allow view if
principal.role == "viewer" and
action == "read";
deny delete if
action == "delete" and
not principal.role == "admin";| Operator | Example | Description |
|---|---|---|
== != |
action == "read" |
Equality / inequality |
< <= > >= |
principal.age >= 18 |
Numeric comparison |
and or not |
a == 1 and not b == 2 |
Logical combinators |
in |
"editor" in user.roles |
Collection search |
is |
actor is User |
Type guard (schema mode) |
has |
resource has owner |
Field existence check |
The in operator searches arrays with structural patterns — extra fields are ignored:
allow access if
{ name: "lhs", value: 10 } in resource.context.namedArguments;Patterns can be literals ("alice", 42, true, null), wildcards (_), objects ({ key: value }), or arrays ([1, 2]).
// Every item must match
allow bulk_read if
forall item in resource.items: item.public == true;
// At least one item must match
allow has_permission if
exists perm in user.permissions: perm.action == "write";Opt into strict typing with use schema; and mod blocks:
use schema;
mod MyApp {
actor User { name String, role String };
resource Document in Folder { owner User, title String };
action "Delete" appliesTo { actor User, resource Document };
};
assert is_owner<User, action, Document> if actor.name == resource.owner.name;
allow delete if MyApp:Delete and resource is Document and is_owner;Policies can declare tests alongside rules:
test "alice can view" {
principal { id: "alice" }
action { id: "view" }
expect allow
}import "shared/roles.karu";
import "rules.karu";For architecture details, see docs/INTERNALS.md.
| Feature | Cedar | Rego | Karu |
|---|---|---|---|
| List Search | ❌ (Strict Schema) | ✅ (Complex syntax) | ✅ (Native in operator) |
| Pattern Matching | ❌ | ✅ | ✅ |
| Strict Mode | ✅ (Usually) | ❌ | ✅ (Optional) |
| Duck Typing | ❌ | ✅ | ✅ |
| Syntax | SQL-like | Datalog | Polar-like |
| Focus | Performance/Safety | Infrastructure | Why not both? |
Karu supports full round-trip conversion with Cedar policies and schemas. See Known Cedar Limitations for current gaps.
Even when running Cedar policies through Karu's import pipeline, evaluation is fast - Karu's native engine evaluates at ~19 million ops/sec, roughly 10× faster than the Cedar-WASM runtime for equivalent policies. For detailed numbers, see BENCHMARKS.md.
cargo add karuuse karu::{compile, rule::Effect};
use serde_json::json;
let policy = compile(r#"allow view if principal == "alice" and action == "view";"#).unwrap();
let input = json!({"principal": "alice", "action": "view", "resource": "doc"});
assert_eq!(policy.evaluate(&input), Effect::Allow);For development setup and contribution guidelines, see CONTRIBUTING.md.
